

<!doctype html>

<html lang="en" data-content_root="../../../">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>skidl.schematics.place &#8212; SKiDL 1.2.2 documentation</title>
    <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=fa44fd50" />
    <link rel="stylesheet" type="text/css" href="../../../_static/bizstyle.css?v=a66e137f" />
    
    <script src="../../../_static/documentation_options.js?v=fd7cadf9"></script>
    <script src="../../../_static/doctools.js?v=9a2dae69"></script>
    <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
    <script src="../../../_static/bizstyle.js"></script>
    <link rel="index" title="Index" href="../../../genindex.html" />
    <link rel="search" title="Search" href="../../../search.html" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <!--[if lt IE 9]>
    <script src="_static/css3-mediaqueries.js"></script>
    <![endif]-->
  </head><body>
    <h1 id="site-title"><a href="../../../../../"><img src="../../../../../images/slim_banner.png" width="100%"></a></h1>
    
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../../../genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="../../../py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="nav-item nav-item-0"><a href="../../../index.html">SKiDL 1.2.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="../../index.html" accesskey="U">Module code</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">skidl.schematics.place</a></li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <h1>Source code for skidl.schematics.place</h1><div class="highlight"><pre>
<span></span><span class="c1"># -*- coding: utf-8 -*-</span>

<span class="c1"># The MIT License (MIT) - Copyright (c) Dave Vandenbout.</span>

<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Autoplacer for arranging symbols in a schematic.</span>
<span class="sd">&quot;&quot;&quot;</span>

<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="p">(</span>  <span class="c1"># isort:skip</span>
    <span class="n">absolute_import</span><span class="p">,</span>
    <span class="n">division</span><span class="p">,</span>
    <span class="n">print_function</span><span class="p">,</span>
    <span class="n">unicode_literals</span><span class="p">,</span>
<span class="p">)</span>

<span class="kn">import</span> <span class="nn">functools</span>
<span class="kn">import</span> <span class="nn">itertools</span>
<span class="kn">import</span> <span class="nn">math</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">from</span> <span class="nn">builtins</span> <span class="kn">import</span> <span class="nb">range</span><span class="p">,</span> <span class="nb">zip</span>
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">Counter</span><span class="p">,</span> <span class="n">defaultdict</span>
<span class="kn">from</span> <span class="nn">copy</span> <span class="kn">import</span> <span class="n">copy</span>

<span class="k">try</span><span class="p">:</span>
    <span class="kn">from</span> <span class="nn">future</span> <span class="kn">import</span> <span class="n">standard_library</span>
    <span class="n">standard_library</span><span class="o">.</span><span class="n">install_aliases</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
    <span class="k">pass</span>

<span class="kn">from</span> <span class="nn">skidl</span> <span class="kn">import</span> <span class="n">Pin</span>
<span class="kn">from</span> <span class="nn">skidl.utilities</span> <span class="kn">import</span> <span class="n">export_to_all</span><span class="p">,</span> <span class="n">rmv_attr</span><span class="p">,</span> <span class="n">sgn</span>
<span class="kn">from</span> <span class="nn">.debug_draw</span> <span class="kn">import</span> <span class="p">(</span>
    <span class="n">draw_end</span><span class="p">,</span>
    <span class="n">draw_pause</span><span class="p">,</span>
    <span class="n">draw_placement</span><span class="p">,</span>
    <span class="n">draw_redraw</span><span class="p">,</span>
    <span class="n">draw_start</span><span class="p">,</span>
    <span class="n">draw_text</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">.geometry</span> <span class="kn">import</span> <span class="n">BBox</span><span class="p">,</span> <span class="n">Point</span><span class="p">,</span> <span class="n">Segment</span><span class="p">,</span> <span class="n">Tx</span><span class="p">,</span> <span class="n">Vector</span>


<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span>
    <span class="s2">&quot;PlacementFailure&quot;</span><span class="p">,</span>
<span class="p">]</span>


<span class="c1">###################################################################</span>
<span class="c1">#</span>
<span class="c1"># OVERVIEW OF AUTOPLACER</span>
<span class="c1">#</span>
<span class="c1"># The input is a Node containing child nodes and parts. The parts in</span>
<span class="c1"># each child node are placed, and then the blocks for each child are</span>
<span class="c1"># placed along with the parts in this node.</span>
<span class="c1">#</span>
<span class="c1"># The individual parts in a node are separated into groups:</span>
<span class="c1"># 1) multiple groups of parts that are all interconnected by one or</span>
<span class="c1"># more nets, and 2) a single group of parts that are not connected</span>
<span class="c1"># by any explicit nets (i.e., floating parts).</span>
<span class="c1">#</span>
<span class="c1"># Each group of connected parts are placed using force-directed placement.</span>
<span class="c1"># Each net exerts an attractive force pulling parts together, and</span>
<span class="c1"># any overlap of parts exerts a repulsive force pushing them apart.</span>
<span class="c1"># Initially, the attractive force is dominant but, over time, it is</span>
<span class="c1"># decreased while the repulsive force is increased using a weighting</span>
<span class="c1"># factor. After that, any part overlaps are cleared and the parts</span>
<span class="c1"># are aligned to the routing grid.</span>
<span class="c1">#</span>
<span class="c1"># Force-directed placement is also used with the floating parts except</span>
<span class="c1"># the non-existent net forces are replaced by a measure of part similarity.</span>
<span class="c1"># This collects similar parts (such as bypass capacitors) together.</span>
<span class="c1">#</span>
<span class="c1"># The child-node blocks are then arranged with the blocks of connected</span>
<span class="c1"># and floating parts to arrive at a total placement for this node.</span>
<span class="c1">#</span>
<span class="c1">###################################################################</span>


<div class="viewcode-block" id="PlacementFailure">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.PlacementFailure">[docs]</a>
<span class="k">class</span> <span class="nc">PlacementFailure</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Exception raised when parts or blocks could not be placed.&quot;&quot;&quot;</span>

    <span class="k">pass</span></div>



<span class="c1"># Small functions for summing Points and Vectors.</span>
<span class="n">pt_sum</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">pts</span><span class="p">:</span> <span class="nb">sum</span><span class="p">(</span><span class="n">pts</span><span class="p">,</span> <span class="n">Point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="n">force_sum</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">forces</span><span class="p">:</span> <span class="nb">sum</span><span class="p">(</span><span class="n">forces</span><span class="p">,</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">is_net_terminal</span><span class="p">(</span><span class="n">part</span><span class="p">):</span>
    <span class="kn">from</span> <span class="nn">skidl.schematics.net_terminal</span> <span class="kn">import</span> <span class="n">NetTerminal</span>

    <span class="k">return</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">NetTerminal</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">get_snap_pt</span><span class="p">(</span><span class="n">part_or_blk</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Get the point for snapping the Part or PartBlock to the grid.</span>

<span class="sd">    Args:</span>
<span class="sd">        part_or_blk (Part | PartBlock): Object with snap point.</span>

<span class="sd">    Returns:</span>
<span class="sd">        Point: Point for snapping to grid or None if no point found.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">part_or_blk</span><span class="o">.</span><span class="n">pins</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">pt</span>
    <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">part_or_blk</span><span class="o">.</span><span class="n">snap_pt</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>


<span class="k">def</span> <span class="nf">snap_to_grid</span><span class="p">(</span><span class="n">part_or_blk</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Snap Part or PartBlock to grid.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (Part | PartBlk): Object to snap to grid.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># Get the position of the current snap point.</span>
    <span class="n">pt</span> <span class="o">=</span> <span class="n">get_snap_pt</span><span class="p">(</span><span class="n">part_or_blk</span><span class="p">)</span> <span class="o">*</span> <span class="n">part_or_blk</span><span class="o">.</span><span class="n">tx</span>

    <span class="c1"># This is where the snap point should be on the grid.</span>
    <span class="n">snap_pt</span> <span class="o">=</span> <span class="n">pt</span><span class="o">.</span><span class="n">snap</span><span class="p">(</span><span class="n">GRID</span><span class="p">)</span>

    <span class="c1"># This is the required movement to get on-grid.</span>
    <span class="n">mv</span> <span class="o">=</span> <span class="n">snap_pt</span> <span class="o">-</span> <span class="n">pt</span>

    <span class="c1"># Update the object&#39;s transformation matrix.</span>
    <span class="n">snap_tx</span> <span class="o">=</span> <span class="n">Tx</span><span class="p">(</span><span class="n">dx</span><span class="o">=</span><span class="n">mv</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">dy</span><span class="o">=</span><span class="n">mv</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
    <span class="n">part_or_blk</span><span class="o">.</span><span class="n">tx</span> <span class="o">*=</span> <span class="n">snap_tx</span>


<span class="k">def</span> <span class="nf">add_placement_bboxes</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Expand part bounding boxes to include space for subsequent routing.&quot;&quot;&quot;</span>
    <span class="kn">from</span> <span class="nn">skidl.schematics.net_terminal</span> <span class="kn">import</span> <span class="n">NetTerminal</span>

    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="c1"># Placement bbox starts off with the part bbox (including any net labels).</span>
        <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span> <span class="o">=</span> <span class="n">BBox</span><span class="p">()</span>
        <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">lbl_bbox</span><span class="p">)</span>

        <span class="c1"># Compute the routing area for each side based on the number of pins on each side.</span>
        <span class="n">padding</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;U&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;D&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;L&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;R&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">}</span>  <span class="c1"># Min padding of 1 channel per side.</span>
        <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">part</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">pin</span><span class="o">.</span><span class="n">stub</span> <span class="ow">is</span> <span class="kc">False</span> <span class="ow">and</span> <span class="n">pin</span><span class="o">.</span><span class="n">is_connected</span><span class="p">():</span>
                <span class="n">padding</span><span class="p">[</span><span class="n">pin</span><span class="o">.</span><span class="n">orientation</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>

        <span class="c1"># expansion_factor &gt; 1 is used to expand the area for routing around each part,</span>
        <span class="c1"># usually in response to a failed routing phase. But don&#39;t expand the routing</span>
        <span class="c1"># around NetTerminals since those are just used to label wires.</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">NetTerminal</span><span class="p">):</span>
            <span class="n">expansion_factor</span> <span class="o">=</span> <span class="mi">1</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">expansion_factor</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;expansion_factor&quot;</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span>

        <span class="c1"># Add padding for routing to the right and upper sides.</span>
        <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
            <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">max</span>
            <span class="o">+</span> <span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="n">padding</span><span class="p">[</span><span class="s2">&quot;L&quot;</span><span class="p">],</span> <span class="n">padding</span><span class="p">[</span><span class="s2">&quot;D&quot;</span><span class="p">])</span> <span class="o">*</span> <span class="n">GRID</span> <span class="o">*</span> <span class="n">expansion_factor</span><span class="p">)</span>
        <span class="p">)</span>

        <span class="c1"># Add padding for routing to the left and lower sides.</span>
        <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
            <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">min</span>
            <span class="o">-</span> <span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="n">padding</span><span class="p">[</span><span class="s2">&quot;R&quot;</span><span class="p">],</span> <span class="n">padding</span><span class="p">[</span><span class="s2">&quot;U&quot;</span><span class="p">])</span> <span class="o">*</span> <span class="n">GRID</span> <span class="o">*</span> <span class="n">expansion_factor</span><span class="p">)</span>
        <span class="p">)</span>


<span class="k">def</span> <span class="nf">get_enclosing_bbox</span><span class="p">(</span><span class="n">parts</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Return bounding box that encloses all the parts.&quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">BBox</span><span class="p">()</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">add_anchor_pull_pins</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Add positions of anchor and pull pins for attractive net forces between parts.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (list): List of movable parts.</span>
<span class="sd">        nets (list): List of attractive nets between parts.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">add_place_pt</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">pin</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add the point for a pin on the placement boundary of a part.&quot;&quot;&quot;</span>

        <span class="n">pin</span><span class="o">.</span><span class="n">route_pt</span> <span class="o">=</span> <span class="n">pin</span><span class="o">.</span><span class="n">pt</span>  <span class="c1"># For drawing of nets during debugging.</span>
        <span class="n">pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="n">pin</span><span class="o">.</span><span class="n">pt</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">pin</span><span class="o">.</span><span class="n">pt</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">pin</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="s2">&quot;U&quot;</span><span class="p">:</span>
            <span class="n">pin</span><span class="o">.</span><span class="n">place_pt</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">y</span>
        <span class="k">elif</span> <span class="n">pin</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="s2">&quot;D&quot;</span><span class="p">:</span>
            <span class="n">pin</span><span class="o">.</span><span class="n">place_pt</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">y</span>
        <span class="k">elif</span> <span class="n">pin</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="s2">&quot;L&quot;</span><span class="p">:</span>
            <span class="n">pin</span><span class="o">.</span><span class="n">place_pt</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">max</span><span class="o">.</span><span class="n">x</span>
        <span class="k">elif</span> <span class="n">pin</span><span class="o">.</span><span class="n">orientation</span> <span class="o">==</span> <span class="s2">&quot;R&quot;</span><span class="p">:</span>
            <span class="n">pin</span><span class="o">.</span><span class="n">place_pt</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">min</span><span class="o">.</span><span class="n">x</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;Unknown pin orientation.&quot;</span><span class="p">)</span>

    <span class="c1"># Remove any existing anchor and pull pins before making new ones.</span>
    <span class="n">rmv_attr</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;anchor_pins&quot;</span><span class="p">,</span> <span class="s2">&quot;pull_pins&quot;</span><span class="p">))</span>

    <span class="c1"># Add dicts for anchor/pull pins and pin centroids to each movable part.</span>
    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
        <span class="n">part</span><span class="o">.</span><span class="n">pull_pins</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
        <span class="n">part</span><span class="o">.</span><span class="n">pin_ctrs</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>

    <span class="k">if</span> <span class="n">nets</span><span class="p">:</span>
        <span class="c1"># If nets exist, then these parts are interconnected so</span>
        <span class="c1"># assign pins on each net to part anchor and pull pin lists.</span>
        <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">nets</span><span class="p">:</span>
            <span class="c1"># Get net pins that are on movable parts.</span>
            <span class="n">pins</span> <span class="o">=</span> <span class="p">{</span><span class="n">pin</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">net</span><span class="o">.</span><span class="n">pins</span> <span class="k">if</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">}</span>

            <span class="c1"># Get the set of parts with pins on the net.</span>
            <span class="n">net</span><span class="o">.</span><span class="n">parts</span> <span class="o">=</span> <span class="p">{</span><span class="n">pin</span><span class="o">.</span><span class="n">part</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">pins</span><span class="p">}</span>

            <span class="c1"># Add each pin as an anchor on the part that contains it and</span>
            <span class="c1"># as a pull pin on all the other parts that will be pulled by this part.</span>
            <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">pins</span><span class="p">:</span>
                <span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pin</span><span class="p">)</span>
                <span class="n">add_place_pt</span><span class="p">(</span><span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="p">,</span> <span class="n">pin</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">net</span><span class="o">.</span><span class="n">parts</span> <span class="o">-</span> <span class="p">{</span><span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="p">}:</span>
                    <span class="c1"># NetTerminals are pulled towards connected parts, but</span>
                    <span class="c1"># those parts are not attracted towards NetTerminals.</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">is_net_terminal</span><span class="p">(</span><span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="p">):</span>
                        <span class="n">part</span><span class="o">.</span><span class="n">pull_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pin</span><span class="p">)</span>

        <span class="c1"># For each net, assign the centroid of the part&#39;s anchor pins for that net.</span>
        <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">nets</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">net</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]:</span>
                    <span class="n">part</span><span class="o">.</span><span class="n">pin_ctrs</span><span class="p">[</span><span class="n">net</span><span class="p">]</span> <span class="o">=</span> <span class="n">pt_sum</span><span class="p">(</span>
                        <span class="n">pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]</span>
                    <span class="p">)</span> <span class="o">/</span> <span class="nb">len</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span><span class="p">[</span><span class="n">net</span><span class="p">])</span>

    <span class="k">else</span><span class="p">:</span>
        <span class="c1"># There are no nets so these parts are floating freely.</span>
        <span class="c1"># Floating parts are all pulled by each other.</span>
        <span class="n">all_pull_pins</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="c1"># Set anchor at top-most pin so floating part tops will align.</span>
                <span class="n">anchor_pull_pin</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">pins</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">pin</span><span class="p">:</span> <span class="n">pin</span><span class="o">.</span><span class="n">pt</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
                <span class="n">add_place_pt</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">anchor_pull_pin</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
                <span class="c1"># Set anchor for part with no pins at all.</span>
                <span class="n">anchor_pull_pin</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">()</span>
                <span class="n">anchor_pull_pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">max</span>
            <span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span><span class="p">[</span><span class="s2">&quot;similarity&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">anchor_pull_pin</span><span class="p">]</span>
            <span class="n">part</span><span class="o">.</span><span class="n">pull_pins</span><span class="p">[</span><span class="s2">&quot;similarity&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">all_pull_pins</span>
            <span class="n">all_pull_pins</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">anchor_pull_pin</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">save_anchor_pull_pins</span><span class="p">(</span><span class="n">parts</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Save anchor/pull pins for each part before they are changed.&quot;&quot;&quot;</span>
    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="n">part</span><span class="o">.</span><span class="n">saved_anchor_pins</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span><span class="p">)</span>
        <span class="n">part</span><span class="o">.</span><span class="n">saved_pull_pins</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">pull_pins</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">restore_anchor_pull_pins</span><span class="p">(</span><span class="n">parts</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Restore the original anchor/pull pin lists for each Part.&quot;&quot;&quot;</span>

    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="s2">&quot;saved_anchor_pins&quot;</span><span class="p">):</span>
            <span class="c1"># Saved pin lists exist, so restore them to the original anchor/pull pin lists.</span>
            <span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">saved_anchor_pins</span>
            <span class="n">part</span><span class="o">.</span><span class="n">pull_pins</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">saved_pull_pins</span>

    <span class="c1"># Remove the attributes where the original lists were saved.</span>
    <span class="n">rmv_attr</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;saved_anchor_pins&quot;</span><span class="p">,</span> <span class="s2">&quot;saved_pull_pins&quot;</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">adjust_orientations</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Adjust orientation of parts.</span>

<span class="sd">    Args:</span>
<span class="sd">        parts (list): List of Parts to adjust.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>

<span class="sd">    Returns:</span>
<span class="sd">        bool: True if one or more part orientations were changed. Otherwise, False.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">find_best_orientation</span><span class="p">(</span><span class="n">part</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Each part has 8 possible orientations. Find the best of the 7 alternatives from the starting one.&quot;&quot;&quot;</span>

        <span class="c1"># Store starting orientation.</span>
        <span class="n">part</span><span class="o">.</span><span class="n">prev_tx</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span>

        <span class="c1"># Get centerpoint of part for use when doing rotations/flips.</span>
        <span class="n">part_ctr</span> <span class="o">=</span> <span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span><span class="o">.</span><span class="n">ctr</span>

        <span class="c1"># Now find the orientation that has the largest decrease (or smallest increase) in cost.</span>
        <span class="c1"># Go through four rotations, then flip the part and go through the rotations again.</span>
        <span class="n">best_delta_cost</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;inf&quot;</span><span class="p">)</span>
        <span class="n">calc_starting_cost</span> <span class="o">=</span> <span class="kc">True</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
            <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">4</span><span class="p">):</span>

                <span class="k">if</span> <span class="n">calc_starting_cost</span><span class="p">:</span>
                    <span class="c1"># Calculate the cost of the starting orientation before any changes in orientation.</span>
                    <span class="n">starting_cost</span> <span class="o">=</span> <span class="n">net_tension</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
                    <span class="c1"># Skip the starting orientation but set flag to process the others.</span>
                    <span class="n">calc_starting_cost</span> <span class="o">=</span> <span class="kc">False</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># Calculate the cost of the current orientation.</span>
                    <span class="n">delta_cost</span> <span class="o">=</span> <span class="n">net_tension</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span> <span class="o">-</span> <span class="n">starting_cost</span>
                    <span class="k">if</span> <span class="n">delta_cost</span> <span class="o">&lt;</span> <span class="n">best_delta_cost</span><span class="p">:</span>
                        <span class="c1"># Save the largest decrease in cost and the associated orientation.</span>
                        <span class="n">best_delta_cost</span> <span class="o">=</span> <span class="n">delta_cost</span>
                        <span class="n">best_tx</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span>

                <span class="c1"># Proceed to the next rotation.</span>
                <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="o">-</span><span class="n">part_ctr</span><span class="p">)</span><span class="o">.</span><span class="n">rot_90cw</span><span class="p">()</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">part_ctr</span><span class="p">)</span>

            <span class="c1"># Flip the part and go through the rotations again.</span>
            <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="o">-</span><span class="n">part_ctr</span><span class="p">)</span><span class="o">.</span><span class="n">flip_x</span><span class="p">()</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">part_ctr</span><span class="p">)</span>

        <span class="c1"># Save the largest decrease in cost and the associated orientation.</span>
        <span class="n">part</span><span class="o">.</span><span class="n">delta_cost</span> <span class="o">=</span> <span class="n">best_delta_cost</span>
        <span class="n">part</span><span class="o">.</span><span class="n">delta_cost_tx</span> <span class="o">=</span> <span class="n">best_tx</span>

        <span class="c1"># Restore the original orientation.</span>
        <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">prev_tx</span>

    <span class="c1"># Get the list of parts that don&#39;t have their orientations locked.</span>
    <span class="n">movable_parts</span> <span class="o">=</span> <span class="p">[</span><span class="n">part</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">part</span><span class="o">.</span><span class="n">orientation_locked</span><span class="p">]</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">movable_parts</span><span class="p">:</span>
        <span class="c1"># No movable parts, so exit without doing anything.</span>
        <span class="k">return</span>

    <span class="c1"># Kernighan-Lin algorithm for finding near-optimal part orientations.</span>
    <span class="c1"># Because of the way the tension for part alignment is computed based on</span>
    <span class="c1"># the nearest part, it is possible for an infinite loop to occur.</span>
    <span class="c1"># Hence the ad-hoc loop limit.</span>
    <span class="k">for</span> <span class="n">iter_cnt</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
        <span class="c1"># Find the best part to move and move it until there are no more parts to move.</span>
        <span class="n">moved_parts</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="n">unmoved_parts</span> <span class="o">=</span> <span class="n">movable_parts</span><span class="p">[:]</span>
        <span class="k">while</span> <span class="n">unmoved_parts</span><span class="p">:</span>
            <span class="c1"># Find the best current orientation for each unmoved part.</span>
            <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">unmoved_parts</span><span class="p">:</span>
                <span class="n">find_best_orientation</span><span class="p">(</span><span class="n">part</span><span class="p">)</span>

            <span class="c1"># Find the part that has the largest decrease in cost.</span>
            <span class="n">part_to_move</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">unmoved_parts</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">p</span><span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">delta_cost</span><span class="p">)</span>

            <span class="c1"># Reorient the part with the Tx that created the largest decrease in cost.</span>
            <span class="n">part_to_move</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">part_to_move</span><span class="o">.</span><span class="n">delta_cost_tx</span>

            <span class="c1"># Transfer the part from the unmoved to the moved part list.</span>
            <span class="n">unmoved_parts</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">part_to_move</span><span class="p">)</span>
            <span class="n">moved_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">part_to_move</span><span class="p">)</span>

        <span class="c1"># Find the point at which the cost reaches its lowest point.</span>
        <span class="c1"># delta_cost at location i is the change in cost *before* part i is moved.</span>
        <span class="c1"># Start with cost change of zero before any parts are moved.</span>
        <span class="n">delta_costs</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,]</span>
        <span class="n">delta_costs</span><span class="o">.</span><span class="n">extend</span><span class="p">((</span><span class="n">part</span><span class="o">.</span><span class="n">delta_cost</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">moved_parts</span><span class="p">))</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">cost_seq</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">accumulate</span><span class="p">(</span><span class="n">delta_costs</span><span class="p">))</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="c1"># Python 2.7 doesn&#39;t have itertools.accumulate().</span>
            <span class="n">cost_seq</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">delta_costs</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">cost_seq</span><span class="p">)):</span>
                <span class="n">cost_seq</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">cost_seq</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">cost_seq</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
        <span class="n">min_cost</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">cost_seq</span><span class="p">)</span>
        <span class="n">min_index</span> <span class="o">=</span> <span class="n">cost_seq</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">min_cost</span><span class="p">)</span>

        <span class="c1"># Move all the parts after that point back to their starting positions.</span>
        <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">moved_parts</span><span class="p">[</span><span class="n">min_index</span><span class="p">:]:</span>
            <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">prev_tx</span>

        <span class="c1"># Terminate the search if no part orientations were changed.</span>
        <span class="k">if</span> <span class="n">min_index</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">break</span>

    <span class="n">rmv_attr</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;prev_tx&quot;</span><span class="p">,</span> <span class="s2">&quot;delta_cost&quot;</span><span class="p">,</span> <span class="s2">&quot;delta_cost_tx&quot;</span><span class="p">))</span>

    <span class="c1"># Return True if one or more iterations were done, indicating part orientations were changed.</span>
    <span class="k">return</span> <span class="n">iter_cnt</span> <span class="o">&gt;</span> <span class="mi">0</span>


<span class="k">def</span> <span class="nf">net_tension_dist</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Calculate the tension of the nets trying to rotate/flip the part.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (Part): Part affected by forces from other connected parts.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>

<span class="sd">    Returns:</span>
<span class="sd">        float: Total tension on the part.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># Compute the force for each net attached to the part.</span>
    <span class="n">tension</span> <span class="o">=</span> <span class="mf">0.0</span>
    <span class="k">for</span> <span class="n">net</span><span class="p">,</span> <span class="n">anchor_pins</span> <span class="ow">in</span> <span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
        <span class="n">pull_pins</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">pull_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">anchor_pins</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">pull_pins</span><span class="p">:</span>
            <span class="c1"># Skip nets without pulling or anchor points.</span>
            <span class="k">continue</span>

        <span class="c1"># Compute the net force acting on each anchor point on the part.</span>
        <span class="k">for</span> <span class="n">anchor_pin</span> <span class="ow">in</span> <span class="n">anchor_pins</span><span class="p">:</span>
            <span class="c1"># Compute the anchor point&#39;s (x,y).</span>
            <span class="n">anchor_pt</span> <span class="o">=</span> <span class="n">anchor_pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">anchor_pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span>

            <span class="c1"># Find the dist from the anchor point to each pulling point.</span>
            <span class="n">dists</span> <span class="o">=</span> <span class="p">[</span>
                <span class="p">(</span><span class="n">anchor_pt</span> <span class="o">-</span> <span class="n">pp</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">pp</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span><span class="o">.</span><span class="n">magnitude</span> <span class="k">for</span> <span class="n">pp</span> <span class="ow">in</span> <span class="n">pull_pins</span>
            <span class="p">]</span>

            <span class="c1"># Only the closest pulling point affects the tension since that is</span>
            <span class="c1"># probably where the wire routing will go to.</span>
            <span class="n">tension</span> <span class="o">+=</span> <span class="nb">min</span><span class="p">(</span><span class="n">dists</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">tension</span>


<span class="k">def</span> <span class="nf">net_torque_dist</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Calculate the torque of the nets trying to rotate/flip the part.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (Part): Part affected by forces from other connected parts.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>

<span class="sd">    Returns:</span>
<span class="sd">        float: Total torque on the part.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># Part centroid for computing torque.</span>
    <span class="n">ctr</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">ctr</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span>

    <span class="c1"># Get the force multiplier applied to point-to-point nets.</span>
    <span class="n">pt_to_pt_mult</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;pt_to_pt_mult&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>

    <span class="c1"># Compute the torque for each net attached to the part.</span>
    <span class="n">torque</span> <span class="o">=</span> <span class="mf">0.0</span>
    <span class="k">for</span> <span class="n">net</span><span class="p">,</span> <span class="n">anchor_pins</span> <span class="ow">in</span> <span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
        <span class="n">pull_pins</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">pull_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">anchor_pins</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">pull_pins</span><span class="p">:</span>
            <span class="c1"># Skip nets without pulling or anchor points.</span>
            <span class="k">continue</span>

        <span class="n">pull_pin_pts</span> <span class="o">=</span> <span class="p">[</span><span class="n">pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">pull_pins</span><span class="p">]</span>

        <span class="c1"># Multiply the force exerted by point-to-point nets.</span>
        <span class="n">force_mult</span> <span class="o">=</span> <span class="n">pt_to_pt_mult</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">pull_pin_pts</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">1</span> <span class="k">else</span> <span class="mi">1</span>

        <span class="c1"># Compute the net torque acting on each anchor point on the part.</span>
        <span class="k">for</span> <span class="n">anchor_pin</span> <span class="ow">in</span> <span class="n">anchor_pins</span><span class="p">:</span>
            <span class="c1"># Compute the anchor point&#39;s (x,y).</span>
            <span class="n">anchor_pt</span> <span class="o">=</span> <span class="n">anchor_pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span>

            <span class="c1"># Compute torque around part center from force between anchor &amp; pull pins.</span>
            <span class="n">normalize</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">pull_pin_pts</span><span class="p">)</span>
            <span class="n">lever_norm</span> <span class="o">=</span> <span class="p">(</span><span class="n">anchor_pt</span> <span class="o">-</span> <span class="n">ctr</span><span class="p">)</span><span class="o">.</span><span class="n">norm</span>
            <span class="k">for</span> <span class="n">pull_pt</span> <span class="ow">in</span> <span class="n">pull_pin_pts</span><span class="p">:</span>
                <span class="n">frc_norm</span> <span class="o">=</span> <span class="p">(</span><span class="n">pull_pt</span> <span class="o">-</span> <span class="n">anchor_pt</span><span class="p">)</span><span class="o">.</span><span class="n">norm</span>
                <span class="n">torque</span> <span class="o">+=</span> <span class="n">lever_norm</span><span class="o">.</span><span class="n">xprod</span><span class="p">(</span><span class="n">frc_norm</span><span class="p">)</span> <span class="o">*</span> <span class="n">force_mult</span> <span class="o">/</span> <span class="n">normalize</span>

    <span class="k">return</span> <span class="nb">abs</span><span class="p">(</span><span class="n">torque</span><span class="p">)</span>


<span class="c1"># Select the net tension method used for the adjusting the orientation of parts.</span>
<span class="n">net_tension</span> <span class="o">=</span> <span class="n">net_tension_dist</span>
<span class="c1"># net_tension = net_torque_dist</span>


<div class="viewcode-block" id="net_force_dist">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.net_force_dist">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">net_force_dist</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Compute attractive force on a part from all the other parts connected to it.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (Part): Part affected by forces from other connected parts.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>

<span class="sd">    Returns:</span>
<span class="sd">        Vector: Force upon given part.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># Get the anchor and pull pins for each net connected to this part.</span>
    <span class="n">anchor_pins</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span>
    <span class="n">pull_pins</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">pull_pins</span>

    <span class="c1"># Get the force multiplier applied to point-to-point nets.</span>
    <span class="n">pt_to_pt_mult</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;pt_to_pt_mult&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>

    <span class="c1"># Compute the total force on the part from all the anchor/pulling points on each net.</span>
    <span class="n">total_force</span> <span class="o">=</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

    <span class="c1"># Parts with a lot of pins can accumulate large net forces that move them very quickly.</span>
    <span class="c1"># Accumulate the number of individual net forces and use that to attenuate</span>
    <span class="c1"># the total force, effectively normalizing the forces between large &amp; small parts.</span>
    <span class="n">net_normalizer</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="c1"># Compute the force for each net attached to the part.</span>
    <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">anchor_pins</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">anchor_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">pull_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]:</span>
            <span class="c1"># Skip nets without pulling or anchor points.</span>
            <span class="k">continue</span>

        <span class="c1"># Multiply the force exerted by point-to-point nets.</span>
        <span class="n">force_mult</span> <span class="o">=</span> <span class="n">pt_to_pt_mult</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">pull_pins</span><span class="p">[</span><span class="n">net</span><span class="p">])</span> <span class="o">&lt;=</span> <span class="mi">1</span> <span class="k">else</span> <span class="mi">1</span>

        <span class="c1"># Initialize net force.</span>
        <span class="n">net_force</span> <span class="o">=</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

        <span class="n">pin_normalizer</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="c1"># Compute the anchor and pulling point (x,y)s for the net.</span>
        <span class="n">anchor_pts</span> <span class="o">=</span> <span class="p">[</span><span class="n">pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">anchor_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]]</span>
        <span class="n">pull_pts</span> <span class="o">=</span> <span class="p">[</span><span class="n">pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">pull_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]]</span>

        <span class="c1"># Compute the net force acting on each anchor point on the part.</span>
        <span class="k">for</span> <span class="n">anchor_pt</span> <span class="ow">in</span> <span class="n">anchor_pts</span><span class="p">:</span>
            <span class="c1"># Sum the forces from each pulling point on the anchor point.</span>
            <span class="k">for</span> <span class="n">pull_pt</span> <span class="ow">in</span> <span class="n">pull_pts</span><span class="p">:</span>
                <span class="c1"># Get the distance from the pull pt to the anchor point.</span>
                <span class="n">dist_vec</span> <span class="o">=</span> <span class="n">pull_pt</span> <span class="o">-</span> <span class="n">anchor_pt</span>

                <span class="c1"># Add the force on the anchor pin from the pulling pin.</span>
                <span class="n">net_force</span> <span class="o">+=</span> <span class="n">dist_vec</span>

                <span class="c1"># Increment the normalizer for every pull force added to the net force.</span>
                <span class="n">pin_normalizer</span> <span class="o">+=</span> <span class="mi">1</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;pin_normalize&quot;</span><span class="p">):</span>
            <span class="c1"># Normalize the net force across all the anchor &amp; pull pins.</span>
            <span class="n">pin_normalizer</span> <span class="o">=</span> <span class="n">pin_normalizer</span> <span class="ow">or</span> <span class="mi">1</span>  <span class="c1"># Prevent div-by-zero.</span>
            <span class="n">net_force</span> <span class="o">/=</span> <span class="n">pin_normalizer</span>

        <span class="c1"># Accumulate force from this net into the total force on the part.</span>
        <span class="c1"># Multiply force if the net meets stated criteria.</span>
        <span class="n">total_force</span> <span class="o">+=</span> <span class="n">net_force</span> <span class="o">*</span> <span class="n">force_mult</span>

        <span class="c1"># Increment the normalizer for every net force added to the total force.</span>
        <span class="n">net_normalizer</span> <span class="o">+=</span> <span class="mi">1</span>

    <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;net_normalize&quot;</span><span class="p">):</span>
        <span class="c1"># Normalize the total force across all the nets.</span>
        <span class="n">net_normalizer</span> <span class="o">=</span> <span class="n">net_normalizer</span> <span class="ow">or</span> <span class="mi">1</span>  <span class="c1"># Prevent div-by-zero.</span>
        <span class="n">total_force</span> <span class="o">/=</span> <span class="n">net_normalizer</span>

    <span class="k">return</span> <span class="n">total_force</span></div>



<span class="c1"># Select the net force method used for the attraction of parts during placement.</span>
<span class="n">attractive_force</span> <span class="o">=</span> <span class="n">net_force_dist</span>


<div class="viewcode-block" id="overlap_force">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.overlap_force">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">overlap_force</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Compute the repulsive force on a part from overlapping other parts.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (Part): Part affected by forces from other overlapping parts.</span>
<span class="sd">        parts (list): List of parts to check for overlaps.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>

<span class="sd">    Returns:</span>
<span class="sd">        Vector: Force upon given part.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># Bounding box of given part.</span>
    <span class="n">part_bbox</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span>

    <span class="c1"># Compute the overlap force of the bbox of this part with every other part.</span>
    <span class="n">total_force</span> <span class="o">=</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">other_part</span> <span class="ow">in</span> <span class="nb">set</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span> <span class="o">-</span> <span class="p">{</span><span class="n">part</span><span class="p">}:</span>
        <span class="n">other_part_bbox</span> <span class="o">=</span> <span class="n">other_part</span><span class="o">.</span><span class="n">place_bbox</span> <span class="o">*</span> <span class="n">other_part</span><span class="o">.</span><span class="n">tx</span>

        <span class="c1"># No force unless parts overlap.</span>
        <span class="k">if</span> <span class="n">part_bbox</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="n">other_part_bbox</span><span class="p">):</span>
            <span class="c1"># Compute the movement needed to separate the bboxes in left/right/up/down directions.</span>
            <span class="c1"># Add some small random offset to break symmetry when parts exactly overlay each other.</span>
            <span class="c1"># Move right edge of part to the left of other part&#39;s left edge, etc...</span>
            <span class="n">moves</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="n">rnd</span> <span class="o">=</span> <span class="n">Vector</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span><span class="o">-</span><span class="mf">0.5</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">edges</span><span class="p">,</span> <span class="nb">dir</span> <span class="ow">in</span> <span class="p">(((</span><span class="s2">&quot;ll&quot;</span><span class="p">,</span> <span class="s2">&quot;lr&quot;</span><span class="p">),</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">)),</span> <span class="p">((</span><span class="s2">&quot;ul&quot;</span><span class="p">,</span> <span class="s2">&quot;ll&quot;</span><span class="p">),</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">))):</span>
                <span class="n">move</span> <span class="o">=</span> <span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">other_part_bbox</span><span class="p">,</span> <span class="n">edges</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">-</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">part_bbox</span><span class="p">,</span> <span class="n">edges</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">-</span> <span class="n">rnd</span><span class="p">)</span> <span class="o">*</span> <span class="nb">dir</span>
                <span class="n">moves</span><span class="o">.</span><span class="n">append</span><span class="p">([</span><span class="n">move</span><span class="o">.</span><span class="n">magnitude</span><span class="p">,</span> <span class="n">move</span><span class="p">])</span>
                <span class="c1"># Flip edges...</span>
                <span class="n">move</span> <span class="o">=</span> <span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">other_part_bbox</span><span class="p">,</span> <span class="n">edges</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">-</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">part_bbox</span><span class="p">,</span> <span class="n">edges</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">-</span> <span class="n">rnd</span><span class="p">)</span> <span class="o">*</span> <span class="nb">dir</span>
                <span class="n">moves</span><span class="o">.</span><span class="n">append</span><span class="p">([</span><span class="n">move</span><span class="o">.</span><span class="n">magnitude</span><span class="p">,</span> <span class="n">move</span><span class="p">])</span>

            <span class="c1"># Select the smallest move that separates the parts.</span>
            <span class="n">move</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">moves</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">m</span><span class="p">:</span> <span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>

            <span class="c1"># Add the move to the total force on the part.</span>
            <span class="n">total_force</span> <span class="o">+=</span> <span class="n">move</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                
    <span class="k">return</span> <span class="n">total_force</span></div>



<div class="viewcode-block" id="overlap_force_rand">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.overlap_force_rand">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">overlap_force_rand</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Compute the repulsive force on a part from overlapping other parts.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (Part): Part affected by forces from other overlapping parts.</span>
<span class="sd">        parts (list): List of parts to check for overlaps.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>

<span class="sd">    Returns:</span>
<span class="sd">        Vector: Force upon given part.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># Bounding box of given part.</span>
    <span class="n">part_bbox</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span>

    <span class="c1"># Compute the overlap force of the bbox of this part with every other part.</span>
    <span class="n">total_force</span> <span class="o">=</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">other_part</span> <span class="ow">in</span> <span class="nb">set</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span> <span class="o">-</span> <span class="p">{</span><span class="n">part</span><span class="p">}:</span>
        <span class="n">other_part_bbox</span> <span class="o">=</span> <span class="n">other_part</span><span class="o">.</span><span class="n">place_bbox</span> <span class="o">*</span> <span class="n">other_part</span><span class="o">.</span><span class="n">tx</span>

        <span class="c1"># No force unless parts overlap.</span>
        <span class="k">if</span> <span class="n">part_bbox</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="n">other_part_bbox</span><span class="p">):</span>
            <span class="c1"># Compute the movement needed to clear the bboxes in left/right/up/down directions.</span>
            <span class="c1"># Add some small random offset to break symmetry when parts exactly overlay each other.</span>
            <span class="c1"># Move right edge of part to the left of other part&#39;s left edge.</span>
            <span class="n">moves</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="n">rnd</span> <span class="o">=</span> <span class="n">Vector</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span><span class="o">-</span><span class="mf">0.5</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">edges</span><span class="p">,</span> <span class="nb">dir</span> <span class="ow">in</span> <span class="p">(((</span><span class="s2">&quot;ll&quot;</span><span class="p">,</span> <span class="s2">&quot;lr&quot;</span><span class="p">),</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">)),</span> <span class="p">((</span><span class="s2">&quot;lr&quot;</span><span class="p">,</span> <span class="s2">&quot;ll&quot;</span><span class="p">),</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">)),</span>
                          <span class="p">((</span><span class="s2">&quot;ul&quot;</span><span class="p">,</span> <span class="s2">&quot;ll&quot;</span><span class="p">),</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">)),</span> <span class="p">((</span><span class="s2">&quot;ll&quot;</span><span class="p">,</span> <span class="s2">&quot;ul&quot;</span><span class="p">),</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">))):</span>
                <span class="n">move</span> <span class="o">=</span> <span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">other_part_bbox</span><span class="p">,</span> <span class="n">edges</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">-</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">part_bbox</span><span class="p">,</span> <span class="n">edges</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">-</span> <span class="n">rnd</span><span class="p">)</span> <span class="o">*</span> <span class="nb">dir</span>
                <span class="n">moves</span><span class="o">.</span><span class="n">append</span><span class="p">([</span><span class="n">move</span><span class="o">.</span><span class="n">magnitude</span><span class="p">,</span> <span class="n">move</span><span class="p">])</span>
            <span class="n">accum</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="k">for</span> <span class="n">move</span> <span class="ow">in</span> <span class="n">moves</span><span class="p">:</span>
                <span class="n">accum</span> <span class="o">+=</span> <span class="n">move</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">for</span> <span class="n">move</span> <span class="ow">in</span> <span class="n">moves</span><span class="p">:</span>
                <span class="n">move</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">accum</span> <span class="o">-</span> <span class="n">move</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">new_accum</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="k">for</span> <span class="n">move</span> <span class="ow">in</span> <span class="n">moves</span><span class="p">:</span>
                <span class="n">move</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="n">new_accum</span>
                <span class="n">new_accum</span> <span class="o">=</span> <span class="n">move</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">select</span> <span class="o">=</span> <span class="n">new_accum</span> <span class="o">*</span> <span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span>
            <span class="k">for</span> <span class="n">move</span> <span class="ow">in</span> <span class="n">moves</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">move</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">select</span><span class="p">:</span>
                    <span class="n">total_force</span> <span class="o">+=</span> <span class="n">move</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                    <span class="k">break</span>
                
    <span class="k">return</span> <span class="n">total_force</span></div>



<span class="c1"># Select the overlap force method used for the repulsion of parts during placement.</span>
<span class="n">repulsive_force</span> <span class="o">=</span> <span class="n">overlap_force</span>
<span class="c1"># repulsive_force = overlap_force_rand</span>


<span class="k">def</span> <span class="nf">scale_attractive_repulsive_forces</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="n">force_func</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Set scaling between attractive net forces and repulsive part overlap forces.&quot;&quot;&quot;</span>

    <span class="c1"># Store original part placement.</span>
    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="n">part</span><span class="o">.</span><span class="n">original_tx</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span>

    <span class="c1"># Find attractive forces when they are maximized by random part placement.</span>
    <span class="n">random_placement</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
    <span class="n">attractive_forces_sum</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span>
        <span class="n">force_func</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span><span class="o">.</span><span class="n">magnitude</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">parts</span>
    <span class="p">)</span>

    <span class="c1"># Find repulsive forces when they are maximized by compacted part placement.</span>
    <span class="n">central_placement</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
    <span class="n">repulsive_forces_sum</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span>
        <span class="n">force_func</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span><span class="o">.</span><span class="n">magnitude</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">parts</span>
    <span class="p">)</span>

    <span class="c1"># Restore original part placement.</span>
    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">original_tx</span>
    <span class="n">rmv_attr</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="p">[</span><span class="s2">&quot;original_tx&quot;</span><span class="p">])</span>

    <span class="c1"># Return scaling factor that makes attractive forces about the same as repulsive forces.</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">repulsive_forces_sum</span> <span class="o">/</span> <span class="n">attractive_forces_sum</span>
    <span class="k">except</span> <span class="ne">ZeroDivisionError</span><span class="p">:</span>
        <span class="c1"># No attractive forces, so who cares about scaling? Set it to 1.</span>
        <span class="k">return</span> <span class="mi">1</span>


<span class="k">def</span> <span class="nf">total_part_force</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="n">scale</span><span class="p">,</span> <span class="n">alpha</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Compute the total of the attractive net and repulsive overlap forces on a part.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (Part): Part affected by forces from other overlapping parts.</span>
<span class="sd">        parts (list): List of parts to check for overlaps.</span>
<span class="sd">        scale (float): Scaling factor for net forces to make them equivalent to overlap forces.</span>
<span class="sd">        alpha (float): Fraction of the total that is the overlap force (range [0,1]).</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>

<span class="sd">    Returns:</span>
<span class="sd">        Vector: Weighted total of net attractive and overlap repulsion forces.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">force</span> <span class="o">=</span> <span class="n">scale</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">alpha</span><span class="p">)</span> <span class="o">*</span> <span class="n">attractive_force</span><span class="p">(</span>
        <span class="n">part</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
    <span class="p">)</span> <span class="o">+</span> <span class="n">alpha</span> <span class="o">*</span> <span class="n">repulsive_force</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
    <span class="n">part</span><span class="o">.</span><span class="n">force</span> <span class="o">=</span> <span class="n">force</span>  <span class="c1"># For debug drawing.</span>
    <span class="k">return</span> <span class="n">force</span>


<span class="k">def</span> <span class="nf">similarity_force</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="n">similarity</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Compute attractive force on a part from all the other parts connected to it.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (Part): Part affected by similarity forces with other parts.</span>
<span class="sd">        similarity (dict): Similarity score for any pair of parts used as keys.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>

<span class="sd">    Returns:</span>
<span class="sd">        Vector: Force upon given part.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># Get the single anchor point for similarity forces affecting this part.</span>
    <span class="n">anchor_pt</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">anchor_pins</span><span class="p">[</span><span class="s2">&quot;similarity&quot;</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span>

    <span class="c1"># Compute the combined force of all the similarity pulling points.</span>
    <span class="n">total_force</span> <span class="o">=</span> <span class="n">Vector</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">pull_pin</span> <span class="ow">in</span> <span class="n">part</span><span class="o">.</span><span class="n">pull_pins</span><span class="p">[</span><span class="s2">&quot;similarity&quot;</span><span class="p">]:</span>
        <span class="n">pull_pt</span> <span class="o">=</span> <span class="n">pull_pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">pull_pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span>
        <span class="c1"># Force from pulling to anchor point is proportional to part similarity and distance.</span>
        <span class="n">total_force</span> <span class="o">+=</span> <span class="p">(</span><span class="n">pull_pt</span> <span class="o">-</span> <span class="n">anchor_pt</span><span class="p">)</span> <span class="o">*</span> <span class="n">similarity</span><span class="p">[</span><span class="n">part</span><span class="p">][</span><span class="n">pull_pin</span><span class="o">.</span><span class="n">part</span><span class="p">]</span>

    <span class="k">return</span> <span class="n">total_force</span>


<span class="k">def</span> <span class="nf">total_similarity_force</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="n">similarity</span><span class="p">,</span> <span class="n">scale</span><span class="p">,</span> <span class="n">alpha</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Compute the total of the attractive similarity and repulsive overlap forces on a part.</span>

<span class="sd">    Args:</span>
<span class="sd">        part (Part): Part affected by forces from other overlapping parts.</span>
<span class="sd">        parts (list): List of parts to check for overlaps.</span>
<span class="sd">        similarity (dict): Similarity score for any pair of parts used as keys.</span>
<span class="sd">        scale (float): Scaling factor for similarity forces to make them equivalent to overlap forces.</span>
<span class="sd">        alpha (float): Proportion of the total that is the overlap force (range [0,1]).</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>

<span class="sd">    Returns:</span>
<span class="sd">        Vector: Weighted total of net attractive and overlap repulsion forces.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">force</span> <span class="o">=</span> <span class="n">scale</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">alpha</span><span class="p">)</span> <span class="o">*</span> <span class="n">similarity_force</span><span class="p">(</span>
        <span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="n">similarity</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
    <span class="p">)</span> <span class="o">+</span> <span class="n">alpha</span> <span class="o">*</span> <span class="n">repulsive_force</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
    <span class="n">part</span><span class="o">.</span><span class="n">force</span> <span class="o">=</span> <span class="n">force</span>  <span class="c1"># For debug drawing.</span>
    <span class="k">return</span> <span class="n">force</span>


<span class="k">def</span> <span class="nf">define_placement_bbox</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Return a bounding box big enough to hold the parts being placed.&quot;&quot;&quot;</span>

    <span class="c1"># Compute appropriate size to hold the parts based on their areas.</span>
    <span class="n">area</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="n">area</span> <span class="o">+=</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">area</span>
    <span class="n">side</span> <span class="o">=</span> <span class="mi">3</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">area</span><span class="p">)</span>  <span class="c1"># HACK: Multiplier is ad-hoc.</span>
    <span class="k">return</span> <span class="n">BBox</span><span class="p">(</span><span class="n">Point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">Point</span><span class="p">(</span><span class="n">side</span><span class="p">,</span> <span class="n">side</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">central_placement</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Cluster all part centroids onto a common point.</span>

<span class="sd">    Args:</span>
<span class="sd">        parts (list): List of Parts.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">:</span>
        <span class="c1"># No need to do placement if there&#39;s less than two parts.</span>
        <span class="k">return</span>

    <span class="c1"># Find the centroid of all the parts.</span>
    <span class="n">ctr</span> <span class="o">=</span> <span class="n">get_enclosing_bbox</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span><span class="o">.</span><span class="n">ctr</span>

    <span class="c1"># Collapse all the parts to the centroid.</span>
    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="n">mv</span> <span class="o">=</span> <span class="n">ctr</span> <span class="o">-</span> <span class="n">part</span><span class="o">.</span><span class="n">place_bbox</span><span class="o">.</span><span class="n">ctr</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span>
        <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="o">*=</span> <span class="n">Tx</span><span class="p">(</span><span class="n">dx</span><span class="o">=</span><span class="n">mv</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">dy</span><span class="o">=</span><span class="n">mv</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">random_placement</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Randomly place parts within an appropriately-sized area.</span>

<span class="sd">    Args:</span>
<span class="sd">        parts (list): List of Parts to place.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># Compute appropriate size to hold the parts based on their areas.</span>
    <span class="n">bbox</span> <span class="o">=</span> <span class="n">define_placement_bbox</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

    <span class="c1"># Place parts randomly within area.</span>
    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="n">pt</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span> <span class="o">*</span> <span class="n">bbox</span><span class="o">.</span><span class="n">w</span><span class="p">,</span> <span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span> <span class="o">*</span> <span class="n">bbox</span><span class="o">.</span><span class="n">h</span><span class="p">)</span>
        <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">pt</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">push_and_pull</span><span class="p">(</span><span class="n">anchored_parts</span><span class="p">,</span> <span class="n">mobile_parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">force_func</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Move parts under influence of attractive nets and repulsive part overlaps.</span>

<span class="sd">    Args:</span>
<span class="sd">        anchored_parts (list): Set of immobile Parts whose position affects placement.</span>
<span class="sd">        mobile_parts (list): Set of Parts that can be moved.</span>
<span class="sd">        nets (list): List of nets that interconnect parts.</span>
<span class="sd">        force_func: Function for calculating forces between parts.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;use_push_pull&quot;</span><span class="p">):</span>
        <span class="c1"># Abort if push &amp; pull of parts is disabled.</span>
        <span class="k">return</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">mobile_parts</span><span class="p">:</span>
        <span class="c1"># No need to do placement if there&#39;s nothing to move.</span>
        <span class="k">return</span>

    <span class="k">def</span> <span class="nf">cost</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="n">alpha</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Cost function for use in debugging. Should decrease as parts move.&quot;&quot;&quot;</span>
        <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
            <span class="n">part</span><span class="o">.</span><span class="n">force</span> <span class="o">=</span> <span class="n">force_func</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="n">scale</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="n">alpha</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">sum</span><span class="p">((</span><span class="n">part</span><span class="o">.</span><span class="n">force</span><span class="o">.</span><span class="n">magnitude</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">))</span>

    <span class="c1"># Get PyGame screen, real-to-screen coord Tx matrix, font for debug drawing.</span>
    <span class="n">scr</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_scr&quot;</span><span class="p">)</span>
    <span class="n">tx</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_tx&quot;</span><span class="p">)</span>
    <span class="n">font</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_font&quot;</span><span class="p">)</span>
    <span class="n">txt_org</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>

    <span class="c1"># Create the total set of parts exerting forces on each other.</span>
    <span class="n">parts</span> <span class="o">=</span> <span class="n">anchored_parts</span> <span class="o">+</span> <span class="n">mobile_parts</span>

    <span class="c1"># If there are no anchored parts, then compute the overall drift force</span>
    <span class="c1"># across all the parts. This will be subtracted so the</span>
    <span class="c1"># entire group of parts doesn&#39;t just continually drift off in one direction.</span>
    <span class="c1"># This only needs to be done if ALL parts are mobile (i.e., no anchored parts).</span>
    <span class="n">rmv_drift</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">anchored_parts</span>

    <span class="c1"># Set scale factor between attractive net forces and repulsive part overlap forces.</span>
    <span class="n">scale</span> <span class="o">=</span> <span class="n">scale_attractive_repulsive_forces</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="n">force_func</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

    <span class="c1"># Setup the schedule for adjusting the alpha coefficient that weights the</span>
    <span class="c1"># combination of the attractive net forces and the repulsive part overlap forces.</span>
    <span class="c1"># Start at 0 (all attractive) and gradually progress to 1 (all repulsive).</span>
    <span class="c1"># Also, set parameters for determining when parts are stable and for restricting</span>
    <span class="c1"># movements in the X &amp; Y directions when parts are being aligned.</span>
    <span class="n">force_schedule</span> <span class="o">=</span> <span class="p">[</span>
        <span class="p">(</span><span class="mf">0.50</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="kc">False</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)),</span>  <span class="c1"># Attractive forces only.</span>
        <span class="p">(</span><span class="mf">0.25</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.01</span><span class="p">,</span> <span class="kc">False</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)),</span>  <span class="c1"># Attractive forces only.</span>
        <span class="c1"># (0.25, 0.2, 0.01, False, (1,1)), # Some repulsive forces.</span>
        <span class="p">(</span><span class="mf">0.25</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="kc">False</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)),</span>  <span class="c1"># More repulsive forces.</span>
        <span class="c1"># (0.25, 0.6, 0.01, False, (1,1)), # More repulsive forces.</span>
        <span class="p">(</span><span class="mf">0.25</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="kc">False</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)),</span>  <span class="c1"># More repulsive forces.</span>
        <span class="c1"># (0.25, 0.7, 0.01, True, (1,0)), # Align parts horiz.</span>
        <span class="c1"># (0.25, 0.7, 0.01, True, (0,1)), # Align parts vert.</span>
        <span class="c1"># (0.25, 0.7, 0.01, True, (1,0)), # Align parts horiz.</span>
        <span class="c1"># (0.25, 0.7, 0.01, True, (0,1)), # Align parts vert.</span>
        <span class="p">(</span><span class="mf">0.25</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.01</span><span class="p">,</span> <span class="kc">False</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)),</span>  <span class="c1"># Remove any part overlaps.</span>
    <span class="p">]</span>
    <span class="c1"># N = 7</span>
    <span class="c1"># force_schedule = [(0.50, i/N, 0.01, False, (1,1)) for i in range(N+1)]</span>

    <span class="c1"># Step through the alpha sequence going from all-attractive to all-repulsive forces.</span>
    <span class="k">for</span> <span class="n">speed</span><span class="p">,</span> <span class="n">alpha</span><span class="p">,</span> <span class="n">stability_coef</span><span class="p">,</span> <span class="n">align_parts</span><span class="p">,</span> <span class="n">force_mask</span> <span class="ow">in</span> <span class="n">force_schedule</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">align_parts</span><span class="p">:</span>
            <span class="c1"># Align parts by only using forces between the closest anchor/pull pins.</span>
            <span class="n">retain_closest_anchor_pull_pins</span><span class="p">(</span><span class="n">mobile_parts</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># For general placement, use forces between all anchor/pull pins.</span>
            <span class="n">restore_anchor_pull_pins</span><span class="p">(</span><span class="n">mobile_parts</span><span class="p">)</span>

        <span class="c1"># This stores the threshold below which all the parts are assumed to be stabilized.</span>
        <span class="c1"># Since it can never be negative, set it to -1 to indicate it&#39;s uninitialized.</span>
        <span class="n">stable_threshold</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>

        <span class="c1"># Move parts for this alpha until they all settle into fixed positions.</span>
        <span class="c1"># Place an iteration limit to prevent an infinite loop.</span>
        <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1000</span><span class="p">):</span>  <span class="c1"># HACK: Ad-hoc iteration limit.</span>
            <span class="c1"># Compute forces exerted on the parts by each other.</span>
            <span class="n">sum_of_forces</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">mobile_parts</span><span class="p">:</span>
                <span class="n">part</span><span class="o">.</span><span class="n">force</span> <span class="o">=</span> <span class="n">force_func</span><span class="p">(</span>
                    <span class="n">part</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="n">scale</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="n">alpha</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
                <span class="p">)</span>
                <span class="c1"># Mask X or Y component of force during part alignment.</span>
                <span class="n">part</span><span class="o">.</span><span class="n">force</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">force</span><span class="o">.</span><span class="n">mask</span><span class="p">(</span><span class="n">force_mask</span><span class="p">)</span>
                <span class="n">sum_of_forces</span> <span class="o">+=</span> <span class="n">part</span><span class="o">.</span><span class="n">force</span><span class="o">.</span><span class="n">magnitude</span>

            <span class="k">if</span> <span class="n">rmv_drift</span><span class="p">:</span>
                <span class="c1"># Calculate the drift force across all parts and subtract it from each part</span>
                <span class="c1"># to prevent them from continually drifting in one direction.</span>
                <span class="n">drift_force</span> <span class="o">=</span> <span class="n">force_sum</span><span class="p">([</span><span class="n">part</span><span class="o">.</span><span class="n">force</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">mobile_parts</span><span class="p">])</span> <span class="o">/</span> <span class="nb">len</span><span class="p">(</span>
                    <span class="n">mobile_parts</span>
                <span class="p">)</span>
                <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">mobile_parts</span><span class="p">:</span>
                    <span class="n">part</span><span class="o">.</span><span class="n">force</span> <span class="o">-=</span> <span class="n">drift_force</span>

            <span class="c1"># Apply movements to part positions.</span>
            <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">mobile_parts</span><span class="p">:</span>
                <span class="n">part</span><span class="o">.</span><span class="n">mv</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">force</span> <span class="o">*</span> <span class="n">speed</span>
                <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="o">*=</span> <span class="n">Tx</span><span class="p">(</span><span class="n">dx</span><span class="o">=</span><span class="n">part</span><span class="o">.</span><span class="n">mv</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">dy</span><span class="o">=</span><span class="n">part</span><span class="o">.</span><span class="n">mv</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>

            <span class="c1"># Keep iterating until all the parts are still.</span>
            <span class="k">if</span> <span class="n">stable_threshold</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
                <span class="c1"># Set the threshold after the first iteration.</span>
                <span class="n">initial_sum_of_forces</span> <span class="o">=</span> <span class="n">sum_of_forces</span>
                <span class="n">stable_threshold</span> <span class="o">=</span> <span class="n">sum_of_forces</span> <span class="o">*</span> <span class="n">stability_coef</span>
            <span class="k">elif</span> <span class="n">sum_of_forces</span> <span class="o">&lt;=</span> <span class="n">stable_threshold</span><span class="p">:</span>
                <span class="c1"># Part positions have stabilized if forces have dropped below threshold.</span>
                <span class="k">break</span>
            <span class="k">elif</span> <span class="n">sum_of_forces</span> <span class="o">&gt;</span> <span class="mi">10</span> <span class="o">*</span> <span class="n">initial_sum_of_forces</span><span class="p">:</span>
                <span class="c1"># If the forces are getting higher, then that usually means the parts are</span>
                <span class="c1"># spreading out. This can happen if speed is too large, so reduce it so</span>
                <span class="c1"># the forces may start to decrease.</span>
                <span class="n">speed</span> <span class="o">*=</span> <span class="mf">0.50</span>

        <span class="k">if</span> <span class="n">scr</span><span class="p">:</span>
            <span class="c1"># Draw current part placement for debugging purposes.</span>
            <span class="n">draw_placement</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">scr</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">font</span><span class="p">)</span>
            <span class="n">draw_text</span><span class="p">(</span>
                <span class="s2">&quot;alpha:</span><span class="si">{alpha:3.2f}</span><span class="s2"> iter:</span><span class="si">{_}</span><span class="s2"> force:</span><span class="si">{sum_of_forces:.1f}</span><span class="s2"> stable:</span><span class="si">{stable_threshold}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
                    <span class="o">**</span><span class="nb">locals</span><span class="p">()</span>
                <span class="p">),</span>
                <span class="n">txt_org</span><span class="p">,</span>
                <span class="n">scr</span><span class="p">,</span>
                <span class="n">tx</span><span class="p">,</span>
                <span class="n">font</span><span class="p">,</span>
                <span class="n">color</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
                <span class="n">real</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">draw_redraw</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">evolve_placement</span><span class="p">(</span><span class="n">anchored_parts</span><span class="p">,</span> <span class="n">mobile_parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">force_func</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Evolve part placement looking for optimum using force function.</span>

<span class="sd">    Args:</span>
<span class="sd">        anchored_parts (list): Set of immobile Parts whose position affects placement.</span>
<span class="sd">        mobile_parts (list): Set of Parts that can be moved.</span>
<span class="sd">        nets (list): List of nets that interconnect parts.</span>
<span class="sd">        force_func (function): Computes the force affecting part positions.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="n">parts</span> <span class="o">=</span> <span class="n">anchored_parts</span> <span class="o">+</span> <span class="n">mobile_parts</span>

    <span class="c1"># Force-directed placement.</span>
    <span class="n">push_and_pull</span><span class="p">(</span><span class="n">anchored_parts</span><span class="p">,</span> <span class="n">mobile_parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">force_func</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

    <span class="c1"># Snap parts to grid.</span>
    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
        <span class="n">snap_to_grid</span><span class="p">(</span><span class="n">part</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">place_net_terminals</span><span class="p">(</span><span class="n">net_terminals</span><span class="p">,</span> <span class="n">placed_parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">force_func</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Place net terminals around already-placed parts.</span>

<span class="sd">    Args:</span>
<span class="sd">        net_terminals (list): List of NetTerminals</span>
<span class="sd">        placed_parts (list): List of placed Parts.</span>
<span class="sd">        nets (list): List of nets that interconnect parts.</span>
<span class="sd">        force_func (function): Computes the force affecting part positions.</span>
<span class="sd">        options (dict): Dict of options and values that enable/disable functions.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">trim_pull_pins</span><span class="p">(</span><span class="n">terminals</span><span class="p">,</span> <span class="n">bbox</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Trim pullpins of NetTerminals to the part pins closest to an edge of the bounding box of placed parts.</span>

<span class="sd">        Args:</span>
<span class="sd">            terminals (list): List of NetTerminals.</span>
<span class="sd">            bbox (BBox): Bounding box of already-placed parts.</span>

<span class="sd">        Note:</span>
<span class="sd">            The rationale for this is that pin closest to an edge of the bounding box will be easier to access.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="n">terminals</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">net</span><span class="p">,</span> <span class="n">pull_pins</span> <span class="ow">in</span> <span class="n">terminal</span><span class="o">.</span><span class="n">pull_pins</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
                <span class="n">insets</span> <span class="o">=</span> <span class="p">[]</span>
                <span class="k">for</span> <span class="n">pull_pin</span> <span class="ow">in</span> <span class="n">pull_pins</span><span class="p">:</span>
                    <span class="n">pull_pt</span> <span class="o">=</span> <span class="n">pull_pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">pull_pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span>

                    <span class="c1"># Get the inset of the terminal pulling pin from each side of the placement area.</span>
                    <span class="c1"># Left side.</span>
                    <span class="n">insets</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="nb">abs</span><span class="p">(</span><span class="n">pull_pt</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ll</span><span class="o">.</span><span class="n">x</span><span class="p">),</span> <span class="n">pull_pin</span><span class="p">))</span>
                    <span class="c1"># Right side.</span>
                    <span class="n">insets</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="nb">abs</span><span class="p">(</span><span class="n">pull_pt</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">lr</span><span class="o">.</span><span class="n">x</span><span class="p">),</span> <span class="n">pull_pin</span><span class="p">))</span>
                    <span class="c1"># Top side.</span>
                    <span class="n">insets</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="nb">abs</span><span class="p">(</span><span class="n">pull_pt</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ul</span><span class="o">.</span><span class="n">y</span><span class="p">),</span> <span class="n">pull_pin</span><span class="p">))</span>
                    <span class="c1"># Bottom side.</span>
                    <span class="n">insets</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="nb">abs</span><span class="p">(</span><span class="n">pull_pt</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ll</span><span class="o">.</span><span class="n">y</span><span class="p">),</span> <span class="n">pull_pin</span><span class="p">))</span>

                <span class="c1"># Retain only the pulling pin closest to an edge of the bounding box (i.e., minimum inset).</span>
                <span class="n">terminal</span><span class="o">.</span><span class="n">pull_pins</span><span class="p">[</span><span class="n">net</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nb">min</span><span class="p">(</span><span class="n">insets</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">off</span><span class="p">:</span> <span class="n">off</span><span class="p">[</span><span class="mi">0</span><span class="p">])[</span><span class="mi">1</span><span class="p">]]</span>

    <span class="k">def</span> <span class="nf">orient</span><span class="p">(</span><span class="n">terminals</span><span class="p">,</span> <span class="n">bbox</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Set orientation of NetTerminals to point away from closest bounding box edge.</span>

<span class="sd">        Args:</span>
<span class="sd">            terminals (list): List of NetTerminals.</span>
<span class="sd">            bbox (BBox): Bounding box of already-placed parts.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="n">terminals</span><span class="p">:</span>
            <span class="c1"># A NetTerminal should already be trimmed so it is attached to a single pin of a part on a single net.</span>
            <span class="n">pull_pin</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">terminal</span><span class="o">.</span><span class="n">pull_pins</span><span class="o">.</span><span class="n">values</span><span class="p">())[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">pull_pt</span> <span class="o">=</span> <span class="n">pull_pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">pull_pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span>

            <span class="c1"># Get the inset of the terminal pulling pin from each side of the placement area</span>
            <span class="c1"># and the Tx() that should be applied if the terminal is placed on that side.</span>
            <span class="n">insets</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="c1"># Left side, so terminal label juts out to the left.</span>
            <span class="n">insets</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="nb">abs</span><span class="p">(</span><span class="n">pull_pt</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ll</span><span class="o">.</span><span class="n">x</span><span class="p">),</span> <span class="n">Tx</span><span class="p">()))</span>
            <span class="c1"># Right side, so terminal label flipped to jut out to the right.</span>
            <span class="n">insets</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="nb">abs</span><span class="p">(</span><span class="n">pull_pt</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">lr</span><span class="o">.</span><span class="n">x</span><span class="p">),</span> <span class="n">Tx</span><span class="p">()</span><span class="o">.</span><span class="n">flip_x</span><span class="p">()))</span>
            <span class="c1"># Top side, so terminal label rotated by 270 to jut out to the top.</span>
            <span class="n">insets</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="nb">abs</span><span class="p">(</span><span class="n">pull_pt</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ul</span><span class="o">.</span><span class="n">y</span><span class="p">),</span> <span class="n">Tx</span><span class="p">()</span><span class="o">.</span><span class="n">rot_90cw</span><span class="p">()</span><span class="o">.</span><span class="n">rot_90cw</span><span class="p">()</span><span class="o">.</span><span class="n">rot_90cw</span><span class="p">()))</span>
            <span class="c1"># Bottom side. so terminal label rotated 90 to jut out to the bottom.</span>
            <span class="n">insets</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="nb">abs</span><span class="p">(</span><span class="n">pull_pt</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ll</span><span class="o">.</span><span class="n">y</span><span class="p">),</span> <span class="n">Tx</span><span class="p">()</span><span class="o">.</span><span class="n">rot_90cw</span><span class="p">()))</span>

            <span class="c1"># Apply the Tx() for the side the terminal is closest to.</span>
            <span class="n">terminal</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">insets</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">inset</span><span class="p">:</span> <span class="n">inset</span><span class="p">[</span><span class="mi">0</span><span class="p">])[</span><span class="mi">1</span><span class="p">]</span>

    <span class="k">def</span> <span class="nf">move_to_pull_pin</span><span class="p">(</span><span class="n">terminals</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Move NetTerminals immediately to their pulling pins.&quot;&quot;&quot;</span>
        <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="n">terminals</span><span class="p">:</span>
            <span class="n">anchor_pin</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">terminal</span><span class="o">.</span><span class="n">anchor_pins</span><span class="o">.</span><span class="n">values</span><span class="p">())[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">anchor_pt</span> <span class="o">=</span> <span class="n">anchor_pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">anchor_pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span>
            <span class="n">pull_pin</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">terminal</span><span class="o">.</span><span class="n">pull_pins</span><span class="o">.</span><span class="n">values</span><span class="p">())[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">pull_pt</span> <span class="o">=</span> <span class="n">pull_pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">pull_pin</span><span class="o">.</span><span class="n">part</span><span class="o">.</span><span class="n">tx</span>
            <span class="n">terminal</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">terminal</span><span class="o">.</span><span class="n">tx</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">pull_pt</span> <span class="o">-</span> <span class="n">anchor_pt</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">evolution</span><span class="p">(</span><span class="n">net_terminals</span><span class="p">,</span> <span class="n">placed_parts</span><span class="p">,</span> <span class="n">bbox</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Evolve placement of NetTerminals starting from outermost from center to innermost.&quot;&quot;&quot;</span>

        <span class="n">evolution_type</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;terminal_evolution&quot;</span><span class="p">,</span> <span class="s2">&quot;all_at_once&quot;</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">evolution_type</span> <span class="o">==</span> <span class="s2">&quot;all_at_once&quot;</span><span class="p">:</span>
            <span class="n">evolve_placement</span><span class="p">(</span>
                <span class="n">placed_parts</span><span class="p">,</span> <span class="n">net_terminals</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">total_part_force</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
            <span class="p">)</span>

        <span class="k">elif</span> <span class="n">evolution_type</span> <span class="o">==</span> <span class="s2">&quot;outer_to_inner&quot;</span><span class="p">:</span>
            <span class="c1"># Start off with the previously-placed parts as anchored parts. NetTerminals will be added to this as they are placed.</span>
            <span class="n">anchored_parts</span> <span class="o">=</span> <span class="n">copy</span><span class="p">(</span><span class="n">placed_parts</span><span class="p">)</span>

            <span class="c1"># Sort terminals from outermost to innermost w.r.t. the center.</span>
            <span class="k">def</span> <span class="nf">dist_to_bbox_edge</span><span class="p">(</span><span class="n">term</span><span class="p">):</span>
                <span class="n">pt</span> <span class="o">=</span> <span class="n">term</span><span class="o">.</span><span class="n">pins</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">*</span> <span class="n">term</span><span class="o">.</span><span class="n">tx</span>
                <span class="k">return</span> <span class="nb">min</span><span class="p">((</span>
                    <span class="nb">abs</span><span class="p">(</span><span class="n">pt</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ll</span><span class="o">.</span><span class="n">x</span><span class="p">),</span>
                    <span class="nb">abs</span><span class="p">(</span><span class="n">pt</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">lr</span><span class="o">.</span><span class="n">x</span><span class="p">),</span>
                    <span class="nb">abs</span><span class="p">(</span><span class="n">pt</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ll</span><span class="o">.</span><span class="n">y</span><span class="p">),</span>
                    <span class="nb">abs</span><span class="p">(</span><span class="n">pt</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ul</span><span class="o">.</span><span class="n">y</span><span class="p">))</span>
                <span class="p">)</span>

            <span class="n">terminals</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span>
                <span class="n">net_terminals</span><span class="p">,</span>
                <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">term</span><span class="p">:</span> <span class="n">dist_to_bbox_edge</span><span class="p">(</span><span class="n">term</span><span class="p">),</span>
                <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
            <span class="p">)</span>

            <span class="c1"># Grab terminals starting from the outside and work towards the inside until a terminal intersects a previous one.</span>
            <span class="n">mobile_terminals</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="n">mobile_bboxes</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="k">for</span> <span class="n">terminal</span> <span class="ow">in</span> <span class="n">terminals</span><span class="p">:</span>
                <span class="n">terminal_bbox</span> <span class="o">=</span> <span class="n">terminal</span><span class="o">.</span><span class="n">place_bbox</span> <span class="o">*</span> <span class="n">terminal</span><span class="o">.</span><span class="n">tx</span>
                <span class="n">mobile_terminals</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">terminal</span><span class="p">)</span>
                <span class="n">mobile_bboxes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">terminal_bbox</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">bbox</span> <span class="ow">in</span> <span class="n">mobile_bboxes</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
                    <span class="k">if</span> <span class="n">terminal_bbox</span><span class="o">.</span><span class="n">intersects</span><span class="p">(</span><span class="n">bbox</span><span class="p">):</span>
                        <span class="c1"># The current NetTerminal intersects one of the previously-selected mobile terminals, so evolve the</span>
                        <span class="c1"># placement of all the mobile terminals except the current one.</span>
                        <span class="n">evolve_placement</span><span class="p">(</span>
                            <span class="n">anchored_parts</span><span class="p">,</span>
                            <span class="n">mobile_terminals</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span>
                            <span class="n">nets</span><span class="p">,</span>
                            <span class="n">force_func</span><span class="p">,</span>
                            <span class="o">**</span><span class="n">options</span>
                        <span class="p">)</span>
                        <span class="c1"># Anchor the mobile terminals after their placement is done.</span>
                        <span class="n">anchored_parts</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">mobile_terminals</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
                        <span class="c1"># Remove the placed terminals, leaving only the current terminal.</span>
                        <span class="n">mobile_terminals</span> <span class="o">=</span> <span class="n">mobile_terminals</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">:]</span>
                        <span class="n">mobile_bboxes</span> <span class="o">=</span> <span class="n">mobile_bboxes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">:]</span>

            <span class="k">if</span> <span class="n">mobile_terminals</span><span class="p">:</span>
                <span class="c1"># Evolve placement of any remaining terminals.</span>
                <span class="n">evolve_placement</span><span class="p">(</span>
                    <span class="n">anchored_parts</span><span class="p">,</span> <span class="n">mobile_terminals</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">total_part_force</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
                <span class="p">)</span>

    <span class="n">bbox</span> <span class="o">=</span> <span class="n">get_enclosing_bbox</span><span class="p">(</span><span class="n">placed_parts</span><span class="p">)</span>
    <span class="n">save_anchor_pull_pins</span><span class="p">(</span><span class="n">net_terminals</span><span class="p">)</span>
    <span class="n">trim_pull_pins</span><span class="p">(</span><span class="n">net_terminals</span><span class="p">,</span> <span class="n">bbox</span><span class="p">)</span>
    <span class="n">orient</span><span class="p">(</span><span class="n">net_terminals</span><span class="p">,</span> <span class="n">bbox</span><span class="p">)</span>
    <span class="n">move_to_pull_pin</span><span class="p">(</span><span class="n">net_terminals</span><span class="p">)</span>
    <span class="n">evolution</span><span class="p">(</span><span class="n">net_terminals</span><span class="p">,</span> <span class="n">placed_parts</span><span class="p">,</span> <span class="n">bbox</span><span class="p">)</span>
    <span class="n">restore_anchor_pull_pins</span><span class="p">(</span><span class="n">net_terminals</span><span class="p">)</span>


<div class="viewcode-block" id="Placer">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">class</span> <span class="nc">Placer</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Mixin to add place function to Node class.&quot;&quot;&quot;</span>

<div class="viewcode-block" id="Placer.group_parts">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer.group_parts">[docs]</a>
    <span class="k">def</span> <span class="nf">group_parts</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Group parts in the Node that are connected by internal nets</span>

<span class="sd">        Args:</span>
<span class="sd">            node (Node): Node with parts.</span>
<span class="sd">            options (dict, optional): Dictionary of options and values. Defaults to {}.</span>

<span class="sd">        Returns:</span>
<span class="sd">            list: List of lists of Parts that are connected.</span>
<span class="sd">            list: List of internal nets connecting parts.</span>
<span class="sd">            list: List of Parts that are not connected to anything (floating).</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[]</span>

        <span class="c1"># Extract list of nets having at least one pin in the node.</span>
        <span class="n">internal_nets</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">get_internal_nets</span><span class="p">()</span>

        <span class="c1"># Group all the parts that have some interconnection to each other.</span>
        <span class="c1"># Start with groups of parts on each individual net.</span>
        <span class="n">connected_parts</span> <span class="o">=</span> <span class="p">[</span>
            <span class="nb">set</span><span class="p">(</span><span class="n">pin</span><span class="o">.</span><span class="n">part</span> <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">net</span><span class="o">.</span><span class="n">pins</span> <span class="k">if</span> <span class="n">pin</span><span class="o">.</span><span class="n">part</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">internal_nets</span>
        <span class="p">]</span>

        <span class="c1"># Now join groups that have parts in common.</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">connected_parts</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
            <span class="n">group1</span> <span class="o">=</span> <span class="n">connected_parts</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
            <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">connected_parts</span><span class="p">)):</span>
                <span class="n">group2</span> <span class="o">=</span> <span class="n">connected_parts</span><span class="p">[</span><span class="n">j</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">group1</span> <span class="o">&amp;</span> <span class="n">group2</span><span class="p">:</span>
                    <span class="c1"># If part groups intersect, collect union of parts into one group</span>
                    <span class="c1"># and empty-out the other.</span>
                    <span class="n">connected_parts</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">connected_parts</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">|</span> <span class="n">connected_parts</span><span class="p">[</span><span class="n">j</span><span class="p">]</span>
                    <span class="n">connected_parts</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                    <span class="c1"># No need to check against group1 any more since it has been</span>
                    <span class="c1"># unioned into group2 that will be checked later in the loop.</span>
                    <span class="k">break</span>

        <span class="c1"># Remove any empty groups that were unioned into other groups.</span>
        <span class="n">connected_parts</span> <span class="o">=</span> <span class="p">[</span><span class="n">group</span> <span class="k">for</span> <span class="n">group</span> <span class="ow">in</span> <span class="n">connected_parts</span> <span class="k">if</span> <span class="n">group</span><span class="p">]</span>

        <span class="c1"># Find parts that aren&#39;t connected to anything.</span>
        <span class="n">floating_parts</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">)</span> <span class="o">-</span> <span class="nb">set</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">chain</span><span class="p">(</span><span class="o">*</span><span class="n">connected_parts</span><span class="p">))</span>

        <span class="k">return</span> <span class="n">connected_parts</span><span class="p">,</span> <span class="n">internal_nets</span><span class="p">,</span> <span class="n">floating_parts</span></div>


<div class="viewcode-block" id="Placer.place_connected_parts">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer.place_connected_parts">[docs]</a>
    <span class="k">def</span> <span class="nf">place_connected_parts</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Place individual parts.</span>

<span class="sd">        Args:</span>
<span class="sd">            node (Node): Node with parts.</span>
<span class="sd">            parts (list): List of Part sets connected by nets.</span>
<span class="sd">            nets (list): List of internal Nets connecting the parts.</span>
<span class="sd">            options (dict): Dict of options and values that enable/disable functions.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">parts</span><span class="p">:</span>
            <span class="c1"># Abort if nothing to place.</span>
            <span class="k">return</span>

        <span class="c1"># Add bboxes with surrounding area so parts are not butted against each other.</span>
        <span class="n">add_placement_bboxes</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="c1"># Set anchor and pull pins that determine attractive forces between parts.</span>
        <span class="n">add_anchor_pull_pins</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="c1"># Randomly place connected parts.</span>
        <span class="n">random_placement</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_placement&quot;</span><span class="p">):</span>
            <span class="c1"># Draw the placement for debug purposes.</span>
            <span class="n">bbox</span> <span class="o">=</span> <span class="n">get_enclosing_bbox</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span>
            <span class="n">draw_scr</span><span class="p">,</span> <span class="n">draw_tx</span><span class="p">,</span> <span class="n">draw_font</span> <span class="o">=</span> <span class="n">draw_start</span><span class="p">(</span><span class="n">bbox</span><span class="p">)</span>
            <span class="n">options</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
                <span class="p">{</span><span class="s2">&quot;draw_scr&quot;</span><span class="p">:</span> <span class="n">draw_scr</span><span class="p">,</span> <span class="s2">&quot;draw_tx&quot;</span><span class="p">:</span> <span class="n">draw_tx</span><span class="p">,</span> <span class="s2">&quot;draw_font&quot;</span><span class="p">:</span> <span class="n">draw_font</span><span class="p">}</span>
            <span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;compress_before_place&quot;</span><span class="p">):</span>
            <span class="n">central_placement</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="c1"># Do force-directed placement of the parts in the parts.</span>

        <span class="c1"># Separate the NetTerminals from the other parts.</span>
        <span class="n">net_terminals</span> <span class="o">=</span> <span class="p">[</span><span class="n">part</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span> <span class="k">if</span> <span class="n">is_net_terminal</span><span class="p">(</span><span class="n">part</span><span class="p">)]</span>
        <span class="n">real_parts</span> <span class="o">=</span> <span class="p">[</span><span class="n">part</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">is_net_terminal</span><span class="p">(</span><span class="n">part</span><span class="p">)]</span>

        <span class="c1"># Do the first trial placement.</span>
        <span class="n">evolve_placement</span><span class="p">([],</span> <span class="n">real_parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">total_part_force</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;rotate_parts&quot;</span><span class="p">):</span>
            <span class="c1"># Adjust part orientations after first trial placement is done.</span>
            <span class="k">if</span> <span class="n">adjust_orientations</span><span class="p">(</span><span class="n">real_parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
                <span class="c1"># Some part orientations were changed, so re-do placement.</span>
                <span class="n">evolve_placement</span><span class="p">([],</span> <span class="n">real_parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">total_part_force</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="c1"># Place NetTerminals after all the other parts.</span>
        <span class="n">place_net_terminals</span><span class="p">(</span>
            <span class="n">net_terminals</span><span class="p">,</span> <span class="n">real_parts</span><span class="p">,</span> <span class="n">nets</span><span class="p">,</span> <span class="n">total_part_force</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span>
        <span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_placement&quot;</span><span class="p">):</span>
            <span class="c1"># Pause to look at placement for debugging purposes.</span>
            <span class="n">draw_pause</span><span class="p">()</span></div>


<div class="viewcode-block" id="Placer.place_floating_parts">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer.place_floating_parts">[docs]</a>
    <span class="k">def</span> <span class="nf">place_floating_parts</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Place individual parts.</span>

<span class="sd">        Args:</span>
<span class="sd">            node (Node): Node with parts.</span>
<span class="sd">            parts (list): List of Parts not connected by explicit nets.</span>
<span class="sd">            options (dict): Dict of options and values that enable/disable functions.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">parts</span><span class="p">:</span>
            <span class="c1"># Abort if nothing to place.</span>
            <span class="k">return</span>

        <span class="c1"># Add bboxes with surrounding area so parts are not butted against each other.</span>
        <span class="n">add_placement_bboxes</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span>

        <span class="c1"># Set anchor and pull pins that determine attractive forces between similar parts.</span>
        <span class="n">add_anchor_pull_pins</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="p">[],</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="c1"># Randomly place the floating parts.</span>
        <span class="n">random_placement</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_placement&quot;</span><span class="p">):</span>
            <span class="c1"># Compute the drawing area for the floating parts</span>
            <span class="n">bbox</span> <span class="o">=</span> <span class="n">get_enclosing_bbox</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span>
            <span class="n">draw_scr</span><span class="p">,</span> <span class="n">draw_tx</span><span class="p">,</span> <span class="n">draw_font</span> <span class="o">=</span> <span class="n">draw_start</span><span class="p">(</span><span class="n">bbox</span><span class="p">)</span>
            <span class="n">options</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
                <span class="p">{</span><span class="s2">&quot;draw_scr&quot;</span><span class="p">:</span> <span class="n">draw_scr</span><span class="p">,</span> <span class="s2">&quot;draw_tx&quot;</span><span class="p">:</span> <span class="n">draw_tx</span><span class="p">,</span> <span class="s2">&quot;draw_font&quot;</span><span class="p">:</span> <span class="n">draw_font</span><span class="p">}</span>
            <span class="p">)</span>

        <span class="c1"># For non-connected parts, do placement based on their similarity to each other.</span>
        <span class="n">part_similarity</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="n">defaultdict</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="mi">0</span><span class="p">))</span>
        <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">other_part</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span>
                <span class="c1"># Don&#39;t compute similarity of a part to itself.</span>
                <span class="k">if</span> <span class="n">other_part</span> <span class="ow">is</span> <span class="n">part</span><span class="p">:</span>
                    <span class="k">continue</span>

                <span class="c1"># HACK: Get similarity forces right-sized.</span>
                <span class="n">part_similarity</span><span class="p">[</span><span class="n">part</span><span class="p">][</span><span class="n">other_part</span><span class="p">]</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">similarity</span><span class="p">(</span><span class="n">other_part</span><span class="p">)</span> <span class="o">/</span> <span class="mi">100</span>
                <span class="c1"># part_similarity[part][other_part] = 0.1</span>

            <span class="c1"># Select the top-most pin in each part as the anchor point for force-directed placement.</span>
            <span class="c1"># tx = part.tx</span>
            <span class="c1"># part.anchor_pin = max(part.anchor_pins, key=lambda pin: (pin.place_pt * tx).y)</span>

        <span class="n">force_func</span> <span class="o">=</span> <span class="n">functools</span><span class="o">.</span><span class="n">partial</span><span class="p">(</span>
            <span class="n">total_similarity_force</span><span class="p">,</span> <span class="n">similarity</span><span class="o">=</span><span class="n">part_similarity</span>
        <span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;compress_before_place&quot;</span><span class="p">):</span>
            <span class="c1"># Compress all floating parts together.</span>
            <span class="n">central_placement</span><span class="p">(</span><span class="n">parts</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="c1"># Do force-directed placement of the parts in the group.</span>
        <span class="n">evolve_placement</span><span class="p">([],</span> <span class="n">parts</span><span class="p">,</span> <span class="p">[],</span> <span class="n">force_func</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_placement&quot;</span><span class="p">):</span>
            <span class="c1"># Pause to look at placement for debugging purposes.</span>
            <span class="n">draw_pause</span><span class="p">()</span></div>


<div class="viewcode-block" id="Placer.place_blocks">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer.place_blocks">[docs]</a>
    <span class="k">def</span> <span class="nf">place_blocks</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">connected_parts</span><span class="p">,</span> <span class="n">floating_parts</span><span class="p">,</span> <span class="n">children</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Place blocks of parts and hierarchical sheets.</span>

<span class="sd">        Args:</span>
<span class="sd">            node (Node): Node with parts.</span>
<span class="sd">            connected_parts (list): List of Part sets connected by nets.</span>
<span class="sd">            floating_parts (set): Set of Parts not connected by any of the internal nets.</span>
<span class="sd">            children (list): Child nodes in the hierarchy.</span>
<span class="sd">            non_sheets (list): Hierarchical set of Parts that are visible.</span>
<span class="sd">            sheets (list): List of hierarchical blocks.</span>
<span class="sd">            options (dict): Dict of options and values that enable/disable functions.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Global dict of pull pins for all blocks as they each pull on each other the same way.</span>
        <span class="n">block_pull_pins</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>

        <span class="c1"># Class for movable groups of parts/child nodes.</span>
        <span class="k">class</span> <span class="nc">PartBlock</span><span class="p">:</span>
            <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">src</span><span class="p">,</span> <span class="n">bbox</span><span class="p">,</span> <span class="n">anchor_pt</span><span class="p">,</span> <span class="n">snap_pt</span><span class="p">,</span> <span class="n">tag</span><span class="p">):</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">src</span> <span class="o">=</span> <span class="n">src</span>  <span class="c1"># Source for this block.</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">place_bbox</span> <span class="o">=</span> <span class="n">bbox</span>  <span class="c1"># FIXME: Is this needed if place_bbox includes room for routing?</span>

                <span class="c1"># Create anchor pin to which forces are applied to this block.</span>
                <span class="n">anchor_pin</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">()</span>
                <span class="n">anchor_pin</span><span class="o">.</span><span class="n">part</span> <span class="o">=</span> <span class="bp">self</span>
                <span class="n">anchor_pin</span><span class="o">.</span><span class="n">place_pt</span> <span class="o">=</span> <span class="n">anchor_pt</span>

                <span class="c1"># This block has only a single anchor pin, but it needs to be in a list</span>
                <span class="c1"># in a dict so it can be processed by the part placement functions.</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">anchor_pins</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">anchor_pins</span><span class="p">[</span><span class="s2">&quot;similarity&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">anchor_pin</span><span class="p">]</span>

                <span class="c1"># Anchor pin for this block is also a pulling pin for all other blocks.</span>
                <span class="n">block_pull_pins</span><span class="p">[</span><span class="s2">&quot;similarity&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">anchor_pin</span><span class="p">)</span>

                <span class="c1"># All blocks have the same set of pulling pins because they all pull each other.</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pull_pins</span> <span class="o">=</span> <span class="n">block_pull_pins</span>

                <span class="bp">self</span><span class="o">.</span><span class="n">snap_pt</span> <span class="o">=</span> <span class="n">snap_pt</span>  <span class="c1"># For snapping to grid.</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">Tx</span><span class="p">()</span>  <span class="c1"># For placement.</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">ref</span> <span class="o">=</span> <span class="s2">&quot;REF&quot;</span>  <span class="c1"># Name for block in debug drawing.</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">tag</span> <span class="o">=</span> <span class="n">tag</span>  <span class="c1"># FIXME: what is this for?</span>

        <span class="c1"># Create a list of blocks from the groups of interconnected parts and the group of floating parts.</span>
        <span class="n">part_blocks</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">part_list</span> <span class="ow">in</span> <span class="n">connected_parts</span> <span class="o">+</span> <span class="p">[</span><span class="n">floating_parts</span><span class="p">]:</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">part_list</span><span class="p">:</span>
                <span class="c1"># No parts in this list for some reason...</span>
                <span class="k">continue</span>

            <span class="c1"># Find snapping point and bounding box for this group of parts.</span>
            <span class="n">snap_pt</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">bbox</span> <span class="o">=</span> <span class="n">BBox</span><span class="p">()</span>
            <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">part_list</span><span class="p">:</span>
                <span class="n">bbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">lbl_bbox</span> <span class="o">*</span> <span class="n">part</span><span class="o">.</span><span class="n">tx</span><span class="p">)</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">snap_pt</span><span class="p">:</span>
                    <span class="c1"># Use the first snapping point of a part you can find.</span>
                    <span class="n">snap_pt</span> <span class="o">=</span> <span class="n">get_snap_pt</span><span class="p">(</span><span class="n">part</span><span class="p">)</span>

            <span class="c1"># Tag indicates the type of part block.</span>
            <span class="n">tag</span> <span class="o">=</span> <span class="mi">2</span> <span class="k">if</span> <span class="p">(</span><span class="n">part_list</span> <span class="ow">is</span> <span class="n">floating_parts</span><span class="p">)</span> <span class="k">else</span> <span class="mi">1</span>

            <span class="c1"># pad the bounding box so part blocks don&#39;t butt-up against each other.</span>
            <span class="n">pad</span> <span class="o">=</span> <span class="n">BLK_EXT_PAD</span>
            <span class="n">bbox</span> <span class="o">=</span> <span class="n">bbox</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="n">Vector</span><span class="p">(</span><span class="n">pad</span><span class="p">,</span> <span class="n">pad</span><span class="p">))</span>

            <span class="c1"># Create the part block and place it on the list.</span>
            <span class="n">part_blocks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">PartBlock</span><span class="p">(</span><span class="n">part_list</span><span class="p">,</span> <span class="n">bbox</span><span class="p">,</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ctr</span><span class="p">,</span> <span class="n">snap_pt</span><span class="p">,</span> <span class="n">tag</span><span class="p">))</span>

        <span class="c1"># Add part blocks for child nodes.</span>
        <span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">children</span><span class="p">:</span>
            <span class="c1"># Calculate bounding box of child node.</span>
            <span class="n">bbox</span> <span class="o">=</span> <span class="n">child</span><span class="o">.</span><span class="n">calc_bbox</span><span class="p">()</span>

            <span class="c1"># Set padding for separating bounding box from others.</span>
            <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">flattened</span><span class="p">:</span>
                <span class="c1"># This is a flattened node so the parts will be shown.</span>
                <span class="c1"># Set the padding to include a pad between the parts and the</span>
                <span class="c1"># graphical box that contains them, plus the padding around</span>
                <span class="c1"># the outside of the graphical box.</span>
                <span class="n">pad</span> <span class="o">=</span> <span class="n">BLK_INT_PAD</span> <span class="o">+</span> <span class="n">BLK_EXT_PAD</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># This is an unflattened child node showing no parts on the inside</span>
                <span class="c1"># so just pad around the outside of its graphical box.</span>
                <span class="n">pad</span> <span class="o">=</span> <span class="n">BLK_EXT_PAD</span>
            <span class="n">bbox</span> <span class="o">=</span> <span class="n">bbox</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="n">Vector</span><span class="p">(</span><span class="n">pad</span><span class="p">,</span> <span class="n">pad</span><span class="p">))</span>

            <span class="c1"># Set the grid snapping point and tag for this child node.</span>
            <span class="n">snap_pt</span> <span class="o">=</span> <span class="n">child</span><span class="o">.</span><span class="n">get_snap_pt</span><span class="p">()</span>
            <span class="n">tag</span> <span class="o">=</span> <span class="mi">3</span>  <span class="c1"># Standard child node.</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">snap_pt</span><span class="p">:</span>
                <span class="c1"># No snap point found, so just use the center of the bounding box.</span>
                <span class="n">snap_pt</span> <span class="o">=</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ctr</span>
                <span class="n">tag</span> <span class="o">=</span> <span class="mi">4</span>  <span class="c1"># A child node with no snapping point.</span>

            <span class="c1"># Create the child block and place it on the list.</span>
            <span class="n">part_blocks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">PartBlock</span><span class="p">(</span><span class="n">child</span><span class="p">,</span> <span class="n">bbox</span><span class="p">,</span> <span class="n">bbox</span><span class="o">.</span><span class="n">ctr</span><span class="p">,</span> <span class="n">snap_pt</span><span class="p">,</span> <span class="n">tag</span><span class="p">))</span>

        <span class="c1"># Get ordered list of all block tags. Use this list to tell if tags are</span>
        <span class="c1"># adjacent since there may be missing tags if a particular type of block</span>
        <span class="c1"># isn&#39;t present.</span>
        <span class="n">tags</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">({</span><span class="n">blk</span><span class="o">.</span><span class="n">tag</span> <span class="k">for</span> <span class="n">blk</span> <span class="ow">in</span> <span class="n">part_blocks</span><span class="p">})</span>

        <span class="c1"># Tie the blocks together with strong links between blocks with the same tag,</span>
        <span class="c1"># and weaker links between blocks with adjacent tags. This ties similar</span>
        <span class="c1"># blocks together into &quot;super blocks&quot; and ties the super blocks into a linear</span>
        <span class="c1"># arrangement (1 -&gt; 2 -&gt; 3 -&gt;...).</span>
        <span class="n">blk_attr</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="n">defaultdict</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="mi">0</span><span class="p">))</span>
        <span class="k">for</span> <span class="n">blk</span> <span class="ow">in</span> <span class="n">part_blocks</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">other_blk</span> <span class="ow">in</span> <span class="n">part_blocks</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">blk</span> <span class="ow">is</span> <span class="n">other_blk</span><span class="p">:</span>
                    <span class="c1"># No attraction between a block and itself.</span>
                    <span class="k">continue</span>
                <span class="k">if</span> <span class="n">blk</span><span class="o">.</span><span class="n">tag</span> <span class="o">==</span> <span class="n">other_blk</span><span class="o">.</span><span class="n">tag</span><span class="p">:</span>
                    <span class="c1"># Large attraction between blocks of same type.</span>
                    <span class="n">blk_attr</span><span class="p">[</span><span class="n">blk</span><span class="p">][</span><span class="n">other_blk</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
                <span class="k">elif</span> <span class="nb">abs</span><span class="p">(</span><span class="n">tags</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">blk</span><span class="o">.</span><span class="n">tag</span><span class="p">)</span> <span class="o">-</span> <span class="n">tags</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">other_blk</span><span class="o">.</span><span class="n">tag</span><span class="p">))</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="c1"># Some attraction between blocks of adjacent types.</span>
                    <span class="n">blk_attr</span><span class="p">[</span><span class="n">blk</span><span class="p">][</span><span class="n">other_blk</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.1</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># Otherwise, no attraction between these blocks.</span>
                    <span class="n">blk_attr</span><span class="p">[</span><span class="n">blk</span><span class="p">][</span><span class="n">other_blk</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">part_blocks</span><span class="p">:</span>
            <span class="c1"># Abort if nothing to place.</span>
            <span class="k">return</span>

        <span class="c1"># Start off with a random placement of part blocks.</span>
        <span class="n">random_placement</span><span class="p">(</span><span class="n">part_blocks</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_placement&quot;</span><span class="p">):</span>
            <span class="c1"># Setup to draw the part block placement for debug purposes.</span>
            <span class="n">bbox</span> <span class="o">=</span> <span class="n">get_enclosing_bbox</span><span class="p">(</span><span class="n">part_blocks</span><span class="p">)</span>
            <span class="n">draw_scr</span><span class="p">,</span> <span class="n">draw_tx</span><span class="p">,</span> <span class="n">draw_font</span> <span class="o">=</span> <span class="n">draw_start</span><span class="p">(</span><span class="n">bbox</span><span class="p">)</span>
            <span class="n">options</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
                <span class="p">{</span><span class="s2">&quot;draw_scr&quot;</span><span class="p">:</span> <span class="n">draw_scr</span><span class="p">,</span> <span class="s2">&quot;draw_tx&quot;</span><span class="p">:</span> <span class="n">draw_tx</span><span class="p">,</span> <span class="s2">&quot;draw_font&quot;</span><span class="p">:</span> <span class="n">draw_font</span><span class="p">}</span>
            <span class="p">)</span>

        <span class="c1"># Arrange the part blocks with similarity force-directed placement.</span>
        <span class="n">force_func</span> <span class="o">=</span> <span class="n">functools</span><span class="o">.</span><span class="n">partial</span><span class="p">(</span><span class="n">total_similarity_force</span><span class="p">,</span> <span class="n">similarity</span><span class="o">=</span><span class="n">blk_attr</span><span class="p">)</span>
        <span class="n">evolve_placement</span><span class="p">([],</span> <span class="n">part_blocks</span><span class="p">,</span> <span class="p">[],</span> <span class="n">force_func</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;draw_placement&quot;</span><span class="p">):</span>
            <span class="c1"># Pause to look at placement for debugging purposes.</span>
            <span class="n">draw_pause</span><span class="p">()</span>

        <span class="c1"># Apply the placement moves of the part blocks to their underlying sources.</span>
        <span class="k">for</span> <span class="n">blk</span> <span class="ow">in</span> <span class="n">part_blocks</span><span class="p">:</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="c1"># Update the Tx matrix of the source (usually a child node).</span>
                <span class="n">blk</span><span class="o">.</span><span class="n">src</span><span class="o">.</span><span class="n">tx</span> <span class="o">=</span> <span class="n">blk</span><span class="o">.</span><span class="n">tx</span>
            <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
                <span class="c1"># The source doesn&#39;t have a Tx so it must be a collection of parts.</span>
                <span class="c1"># Apply the block placement to the Tx of each part.</span>
                <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">blk</span><span class="o">.</span><span class="n">src</span><span class="p">:</span>
                    <span class="n">part</span><span class="o">.</span><span class="n">tx</span> <span class="o">*=</span> <span class="n">blk</span><span class="o">.</span><span class="n">tx</span></div>


<div class="viewcode-block" id="Placer.get_attrs">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer.get_attrs">[docs]</a>
    <span class="k">def</span> <span class="nf">get_attrs</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return dict of attribute sets for the parts, pins, and nets in a node.&quot;&quot;&quot;</span>
        <span class="n">attrs</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;parts&quot;</span><span class="p">:</span> <span class="nb">set</span><span class="p">(),</span> <span class="s2">&quot;pins&quot;</span><span class="p">:</span> <span class="nb">set</span><span class="p">(),</span> <span class="s2">&quot;nets&quot;</span><span class="p">:</span> <span class="nb">set</span><span class="p">()}</span>
        <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
            <span class="n">attrs</span><span class="p">[</span><span class="s2">&quot;parts&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="nb">dir</span><span class="p">(</span><span class="n">part</span><span class="p">)))</span>
            <span class="k">for</span> <span class="n">pin</span> <span class="ow">in</span> <span class="n">part</span><span class="o">.</span><span class="n">pins</span><span class="p">:</span>
                <span class="n">attrs</span><span class="p">[</span><span class="s2">&quot;pins&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="nb">dir</span><span class="p">(</span><span class="n">pin</span><span class="p">)))</span>
        <span class="k">for</span> <span class="n">net</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">get_internal_nets</span><span class="p">():</span>
            <span class="n">attrs</span><span class="p">[</span><span class="s2">&quot;nets&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="nb">dir</span><span class="p">(</span><span class="n">net</span><span class="p">)))</span>
        <span class="k">return</span> <span class="n">attrs</span></div>


<div class="viewcode-block" id="Placer.show_added_attrs">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer.show_added_attrs">[docs]</a>
    <span class="k">def</span> <span class="nf">show_added_attrs</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Show attributes that were added to parts, pins, and nets in a node.&quot;&quot;&quot;</span>
        <span class="n">current_attrs</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">get_attrs</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">current_attrs</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
            <span class="nb">print</span><span class="p">(</span>
                <span class="s2">&quot;added </span><span class="si">{}</span><span class="s2"> attrs: </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">current_attrs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">-</span> <span class="n">node</span><span class="o">.</span><span class="n">attrs</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
            <span class="p">)</span></div>


<div class="viewcode-block" id="Placer.rmv_placement_stuff">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer.rmv_placement_stuff">[docs]</a>
    <span class="k">def</span> <span class="nf">rmv_placement_stuff</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Remove attributes added to parts, pins, and nets of a node during the placement phase.&quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
            <span class="n">rmv_attr</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">pins</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;route_pt&quot;</span><span class="p">,</span> <span class="s2">&quot;place_pt&quot;</span><span class="p">))</span>
        <span class="n">rmv_attr</span><span class="p">(</span>
            <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">,</span>
            <span class="p">(</span><span class="s2">&quot;anchor_pins&quot;</span><span class="p">,</span> <span class="s2">&quot;pull_pins&quot;</span><span class="p">,</span> <span class="s2">&quot;pin_ctrs&quot;</span><span class="p">,</span> <span class="s2">&quot;force&quot;</span><span class="p">,</span> <span class="s2">&quot;mv&quot;</span><span class="p">),</span>
        <span class="p">)</span>
        <span class="n">rmv_attr</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">get_internal_nets</span><span class="p">(),</span> <span class="p">(</span><span class="s2">&quot;parts&quot;</span><span class="p">,))</span></div>


<div class="viewcode-block" id="Placer.place">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer.place">[docs]</a>
    <span class="k">def</span> <span class="nf">place</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">tool</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Place the parts and children in this node.</span>

<span class="sd">        Args:</span>
<span class="sd">            node (Node): Hierarchical node containing the parts and children to be placed.</span>
<span class="sd">            tool (str): Backend tool for schematics.</span>
<span class="sd">            options (dict): Dictionary of options and values to control placement.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Inject the constants for the backend tool into this module.</span>
        <span class="kn">import</span> <span class="nn">skidl</span>
        <span class="kn">from</span> <span class="nn">skidl.tools</span> <span class="kn">import</span> <span class="n">tool_modules</span>

        <span class="n">tool</span> <span class="o">=</span> <span class="n">tool</span> <span class="ow">or</span> <span class="n">skidl</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">tool</span>
        <span class="n">this_module</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="vm">__name__</span><span class="p">]</span>
        <span class="n">this_module</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">tool_modules</span><span class="p">[</span><span class="n">tool</span><span class="p">]</span><span class="o">.</span><span class="n">constants</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">)</span>

        <span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;seed&quot;</span><span class="p">))</span>

        <span class="c1"># Store the starting attributes of the node&#39;s parts, pins, and nets.</span>
        <span class="n">node</span><span class="o">.</span><span class="n">attrs</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">get_attrs</span><span class="p">()</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="c1"># First, recursively place children of this node.</span>
            <span class="c1"># TODO: Child nodes are independent, so can they be processed in parallel?</span>
            <span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
                <span class="n">child</span><span class="o">.</span><span class="n">place</span><span class="p">(</span><span class="n">tool</span><span class="o">=</span><span class="n">tool</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

            <span class="c1"># Group parts into those that are connected by explicit nets and</span>
            <span class="c1"># those that float freely connected only by stub nets.</span>
            <span class="n">connected_parts</span><span class="p">,</span> <span class="n">internal_nets</span><span class="p">,</span> <span class="n">floating_parts</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">group_parts</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>

            <span class="c1"># Place each group of connected parts.</span>
            <span class="k">for</span> <span class="n">group</span> <span class="ow">in</span> <span class="n">connected_parts</span><span class="p">:</span>
                <span class="n">node</span><span class="o">.</span><span class="n">place_connected_parts</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">group</span><span class="p">),</span> <span class="n">internal_nets</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

            <span class="c1"># Place the floating parts that have no connections to anything else.</span>
            <span class="n">node</span><span class="o">.</span><span class="n">place_floating_parts</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">floating_parts</span><span class="p">),</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>

            <span class="c1"># Now arrange all the blocks of placed parts and the child nodes within this node.</span>
            <span class="n">node</span><span class="o">.</span><span class="n">place_blocks</span><span class="p">(</span>
                <span class="n">connected_parts</span><span class="p">,</span> <span class="n">floating_parts</span><span class="p">,</span> <span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="o">.</span><span class="n">values</span><span class="p">(),</span> <span class="o">**</span><span class="n">options</span>
            <span class="p">)</span>

            <span class="c1"># Remove any stuff leftover from this place &amp; route run.</span>
            <span class="c1"># print(f&quot;added part attrs = {new_part_attrs}&quot;)</span>
            <span class="n">node</span><span class="o">.</span><span class="n">rmv_placement_stuff</span><span class="p">()</span>
            <span class="c1"># node.show_added_attrs()</span>

            <span class="c1"># Calculate the bounding box for the node after placement of parts and children.</span>
            <span class="n">node</span><span class="o">.</span><span class="n">calc_bbox</span><span class="p">()</span>

        <span class="k">except</span> <span class="n">PlacementFailure</span><span class="p">:</span>
            <span class="n">node</span><span class="o">.</span><span class="n">rmv_placement_stuff</span><span class="p">()</span>
            <span class="k">raise</span> <span class="n">PlacementFailure</span></div>


<div class="viewcode-block" id="Placer.get_snap_pt">
<a class="viewcode-back" href="../../../rst_output/skidl.schematics.place.html#skidl.schematics.place.Placer.get_snap_pt">[docs]</a>
    <span class="k">def</span> <span class="nf">get_snap_pt</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get a Point to use for snapping the node to the grid.</span>

<span class="sd">        Args:</span>
<span class="sd">            node (Node): The Node to which the snapping point applies.</span>

<span class="sd">        Returns:</span>
<span class="sd">            Point: The snapping point or None.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="n">node</span><span class="o">.</span><span class="n">flattened</span><span class="p">:</span>
            <span class="c1"># Look for a snapping point based on one of its parts.</span>
            <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">parts</span><span class="p">:</span>
                <span class="n">snap_pt</span> <span class="o">=</span> <span class="n">get_snap_pt</span><span class="p">(</span><span class="n">part</span><span class="p">)</span>
                <span class="k">if</span> <span class="n">snap_pt</span><span class="p">:</span>
                    <span class="k">return</span> <span class="n">snap_pt</span>

            <span class="c1"># If no part snapping point, look for one in its children.</span>
            <span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
                <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">flattened</span><span class="p">:</span>
                    <span class="n">snap_pt</span> <span class="o">=</span> <span class="n">child</span><span class="o">.</span><span class="n">get_snap_pt</span><span class="p">()</span>
                    <span class="k">if</span> <span class="n">snap_pt</span><span class="p">:</span>
                        <span class="c1"># Apply the child transformation to its snapping point.</span>
                        <span class="k">return</span> <span class="n">snap_pt</span> <span class="o">*</span> <span class="n">child</span><span class="o">.</span><span class="n">tx</span>

        <span class="c1"># No snapping point if node is not flattened or no parts in it or its children.</span>
        <span class="k">return</span> <span class="kc">None</span></div>
</div>

</pre></div>

            <div class="clearer"></div>
          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
<search id="searchbox" style="display: none" role="search">
  <h3 id="searchlabel">Quick search</h3>
    <div class="searchformwrapper">
    <form class="search" action="../../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>
    </div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../../../genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="../../../py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="nav-item nav-item-0"><a href="../../../index.html">SKiDL 1.2.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">skidl.schematics.place</a></li> 
      </ul>
    </div>
    <div class="footer" role="contentinfo">
    &#169; Copyright 2016-2024, Dave Vandenbout.
      Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 7.3.7.
    </div>
  </body>
</html>